2022-7-15 java 数据结构入门
@
数据结构
1.二分查找
动图演示:
前提: 使用二分查找的前提是数组是有序的
int []arr ={1,2,3,4,5,6,7};
Scanner scanner = new Scanner(System.in);
int left = 0;//最左边元素的下标
int right = arr.length-1;//最右边元素的下标
int mid = 0;//中间元素的值
System.out.println("请输入一个数:");
int k = scanner.nextInt();//要查找的元素k
while (left <= right){
mid = (left+right)/2;
if (arr[mid]>k){
right = mid-1;
}
else if (arr[mid]<k){
left = mid+1;
}
else {
break;
}
}
if (left>right){
System.out.println("没有找到该数");
}else {
System.out.println("找到了");
}
2.冒泡排序
1.冒泡排序原理
2.冒泡排序基础版
//按照刚才那个动图进行对应
//冒泡排序两两比较的元素是没有被排序过的元素--->
public void bubbleSort(int[] array){
for(int i=0;i<array.length-1;i++){//控制比较轮次,一共 n-1 趟
for(int j=0;j<array.length-1-i;j++){//控制两个挨着的元素进行比较
if(array[j] > array[j+1]){
int temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
}
3.冒泡排序代码优化版
说明:因为在最后几轮,数组可能已经是有序的了,没有必要再进行循环排序了
- 利用布尔变量 isSorted作为标记。如果在本轮排序中,元素有交换,则说明数列无序;如果没有元素交换,说明数列已然有序,直接跳出大循环
public static int[] bubbleSort(int[] arr) {
if (arr == null || arr.length < 2) {
return arr;
}
for (int i = 0; i < arr.length - 1; i++) {
boolean isSorted = true;//有序标记,每一轮的初始是true
for (int j = 0; j < arr.length -i - 1; j++) {
if (arr[j + 1] < arr[j]) {
isSorted = false;//有元素交换,所以不是有序,标记变为false
int t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
}
}
//一趟下来是否发生位置交换,如果没有交换直接跳出大循环
if(isSorted )
break;
}
return arr;
}
4.冒泡排序代码升级版
如果数列中前半部分是无序的,后半部分是有序的呢?比如(3,4,2,1,5,6,7,8)这个数组,其实后面的许多元素已经是有序的了,但是每一轮还是白白比较了许多次
- 解决方法:在每一轮排序的最后,记录一下最后一次元素交换的位置,那个位置也就是无序数列的边界,再往后就是有序区
public static int[] bubbleSort(int[] arr) {
if (arr == null || arr.length < 2) {
return arr;
}
//记录最后一次交换的位置
int lastExchangeIndex = 0;
//无序数列的边界,每次比较只需要比到这里为止
int sortBorder = arr.length - 1;
for (int i = 0; i < arr.length - 1; i++) {
boolean isSorted = true;//有序标记,每一轮的初始是true
for (int j = 0; j < sortBorder; j++) {
if (arr[j + 1] < arr[j]) {
isSorted = false;//有元素交换,所以不是有序,标记变为false
int t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
lastExchangeIndex = j;
}
}
sortBorder = lastExchangeIndex
//一趟下来是否发生位置交换,如果没有交换直接跳出大循环
if(isSorted )
break;
}
return arr;
}
3.选择排序
1. 算法步骤
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
重复第二步,直到所有元素均排序完毕。
2.插入排序图解:
3.代码
public static void searchSort(int[] arr){
for (int i = 0; i<arr.length - 1; i++){//①
int minIndex = i;
int min = arr[i];//②
for (int j = i + 1; j<arr.length; j++){//③
if(min>arr[j]){
min = arr[j];
minIndex = j;
}
}
arr[minIndex] = arr[i];
arr[i] = min;//④
}
System.out.println(Arrays.toString(arr));
}
①.我们定义一个循环,这个循环就是用来进行上述的每轮排序行为的,在这个循环中,每轮循环都会找到当前数组中的最小值,并让这个最小值和当前数组的首元素进行位置互换。与此同时,循环头中的变量i在这里也有有着丰富的含义,它不仅代表循环的次数,它也代表着每次轮循环中数组的首元素位置,当数组中的首元素位置就是原最大的那个数组中最后一个元素的位置时,就说明排序已经到头,算法可以结束了。
②.我们定义最小值的下标变量,同时定义最小值。这里主要是找最值的方法,找最值的方法一般都是默认数组首节点是最值点,然后对数组进行遍历,在遍历过程中会依次查看整个数组中的所有元素并和最值进行对比,如果发现了比最值小的元素,那么就让当前的数组元素替换掉之前的最值元素成为新的最值元素,如这里使用minIndex保存最值下标,使用min保存最值,当找到数组中新的最值时,新的最值下标就会替换掉minIndex中原来的值,而新的最值也会替换掉min中原来的值。
③.这个循环就是找最值的循环体,具体解释看上文中②的解释。
④.这里的两句代码就是将找到的最值与数组首元素的值进行对换的行为。之后将开启新的一轮循环,新数组将从i开始,而i这时加了1,这就代表着新数组往后“缩”了一格,规模变小了一些。重复进行外循环,直到外循环终止,这个数组最终会被排好序。
4.插入排序
1.插入排序图解
2.算法总结
根据图解,我们现在可以理解插入排序的过程了(以从小到大排序为例):我们将原数组空间看成两个部分,前边是有序部分,后边是无序部分,有序部分我们默认为它就已经是排好序的,它内部已经是从小到大有序的状态了,即使当前它是空的,它也具备这个特征。然后我们不断的取无序数组的首元素,向有序数组的尾部添加,我们在这里并没有真正的将它取出,并且再添加回来,因为根据我们的定义,有序数组的尾部正好就和无序数组的头部相邻,这只是一个更改标记的事情,我们只要把有序数组的长度加1,无序数组的长度减一,并且将有序数组的头部元素指针指向它的下一个,就可以完全准确的代表这个行为。因此这时我们已经将无序数组的首元素取出,并插入在了有序数组的尾部,然而这时,在尾部新加入的元素有可能会导致整个有序数组变得无序,因此我们需要进行调整。而调整方式就是将新加入的元素进行对比并根据对比结果往前移动,这个移动过程有点像冒泡排序的过程:新加入元素和它前边的元素进行对比,如果它比它前边的元素小,则二者互换位置,重复这个行为,直到它前边的元素小于它才会停止,这样一来,有序数组就仍然是有序数组了。我们重复这个向有序数组中插入不断插入数据,并在插入之后通过操作使其变得有序的行为,在这个过程中我们会一个一个的拿走无序数组中的首节点并一个一个单位的减少无序数组的规模,并一个一个的向有序数组中添加并扩大有序数组的规模,直到最后整个无需数组被掏空,有序数组占据了原数组空间的所有空间时,整个数组排序宣告完成。
3.代码
public static void insertSort(int[] arr){
for (int i = 1; i<arr.length; i++){//①
for (int j = i-1; j>=0; j--){//②
if(arr[j]>arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}else
break;
}
}
System.out.println(Arrays.toString(arr));
}
4.代码详解
①标记了外部的大循环,这个循环实际上就是驱动有序数组一个一个增加,无序数组一个一个减少的动力,在此,i就代表了无序数组的首节点位置,因为当数组中有一个元素时它必定有序,所以我们在这里可以忽略掉往插入第一个元素的行为,直接从第二个开始插入。
②标记了外部循环中的一个内循环,外循环的每次执行,实际上都代表了我们将无序数组中的首元素拿下来放到有序数组的尾部,而这里这个内循环,实际上就是移动这个新来的元素,使有序数组重新变得有序的机制,我们可以看到,j指向的是i-1,这个位置就是当前有序数组没有插入新元素之前的尾部位置,在这个循环中,j要一直和j+1进行对比,j+1指向的就是新加入的元素,如果j指向的元素大于j+1指向的元素的话,二者就要进行一个类似冒泡排序的互换,将j+1指向的元素和j指向的元素进行互换,在互换之后,j指向了新加入的元素,而j+1则指向了之前新元素前边的元素,也就是之前的数组尾部,这时j自减一次,这就导致j+1又重新指向了新加入的元素,而j也又指向了新加入的元素的前一个元素,新元素得以继续同它前边的元素进行对比,当经过对比发现,新加入的元素已经大于前边的元素之后,说明新加入的元素已经移动到了自己正确的位置,这个移动行为就可以终止了。
插入排序的精髓在于设置一个有序的空数组,从它为空的时候就认定其为有序数组,并在不断的插入新元素的过程中维护其有序性,这样一来,我们实际上一直在干的事情就是向一个有序数组中不断地插入新元素,这比进行直接排序的操作手法会简单的多。以上就是插入排序。
5.数组反转
// 创建一个字符串的数组
String[] str = new String[]{"AA","BB","CC","DD","EE","FF","GG"};
方式一
临时变量
for(int i = 0; i < str.length / 2; i++){
String temp = str[i];
str[i] = str[str.length - i - 1];
str[str.length - i - 1] = temp;
}
方式二
创建一个新的数组,倒序遍历旧数组中的元素,然后按照顺序复制给新数组,然后再把新数组的值复制到旧数组当中
for(int i = 0,j = str.length - 1; i < j; i++,j--){
// 交换
String temp = str[i];
str[i] = str[j];
str[j] = temp;
}
方式三
创建一个新数组,长度是旧数组的长度。将旧数组倒序遍历获取数组中的元素,拿到元素之后从头开始赋值给新数组当中,最后将新数组的地址值赋值给旧数组
// 方式1.3
String[] newArr = new String[str.length]; // 创建新数组,数组的长度是旧数组的长度
for (int i = str.length - 1, j = 0; i >= 0; i--, j++) {
newArr[j] = str[i];
}
// 循环完毕之后,切记要将newArr数组的地址值赋值给str数组
str = newArr;
// 遍历str数组,查看是否反转了
for(int i = 0; i < str.length; i++){
System.out.print(str[i] + " ");
}
2022-7-15 java 数据结构入门的更多相关文章
- Java 学习(15):Java 数据结构
Java 数据结构 Java工具包提供了强大的数据结构.在Java中的数据结构主要包括以下几种接口和类: 枚举(Enumeration) 位集合(BitSet) 向量(Vector) 栈(Stack) ...
- java秀发入门到优雅秃头路线导航【教学视频+博客+书籍整理】
目录 一.Java基础 二.关于JavaWeb基础 三.关于数据库 四.关于ssm框架 五.关于数据结构与算法 六.关于开发工具idea 七.关于项目管理工具Mawen.Git.SVN.Gradle. ...
- 二、Android NDK编程预备之Java jni入门Hello World
转自: http://www.eoeandroid.com/forum.php?mod=viewthread&tid=264543&fromuid=588695 昨天已经简要介绍了J ...
- C功底挑战Java菜鸟入门概念干货(一)
一.认识Java 1.Java 程序比较特殊,它必须先经过编译,然后再利用解释的方式来运行. 2.Byte-codes 最大的好处是——可越平台运行,可让“一次编写,处处运行”成为可能. 3.使用 ...
- C功底挑战Java菜鸟入门概念干货(二)
(接上篇博文:C功底挑战Java菜鸟入门概念干货(一)) 一.Java面向对象程序设计-类的基本形式 1.“类”是把事物的数据与相关的功能封装在一起,形成的一种特殊结构,用以表达对真实世界的一种抽象概 ...
- java 数据结构 图
以下内容主要来自大话数据结构之中,部分内容参考互联网中其他前辈的博客,主要是在自己理解的基础上进行记录. 图的定义 图是由顶点的有穷非空集合和顶点之间边的集合组成,通过表示为G(V,E),其中,G标示 ...
- Java数据结构和算法
首先,本人自学java,但是只学习了java的基础知识,所以想接下来学习一下数据结构和算法,但是找了很多教材,大部分写的好的都是用c语言实现的,虽然知道数据结构和算法,跟什么语言实现的没有关系,但是我 ...
- Java数据结构和算法(九)——高级排序
春晚好看吗?不存在的!!! 在Java数据结构和算法(三)——冒泡.选择.插入排序算法中我们介绍了三种简单的排序算法,它们的时间复杂度大O表示法都是O(N2),如果数据量少,我们还能忍受,但是数据量大 ...
- Java数据结构和算法 - 堆
堆的介绍 Q: 什么是堆? A: 这里的“堆”是指一种特殊的二叉树,不要和Java.C/C++等编程语言里的“堆”混淆,后者指的是程序员用new能得到的计算机内存的可用部分 A: 堆是有如下特点的二叉 ...
随机推荐
- keepalived安装及配置文件详解
一个执着于技术的公众号 在上一篇文章中,我们对Keepalived进行了简单入门学习: Keepalived入门学习 今天我们继续学习Keepalived服务. 一.安装Keepalived服务 两种 ...
- 关于利用STL栈求解四则中缀表达式以及中缀表达式转逆波兰表达式和逆波兰表达式的求解
今天总结一下栈的一个重要应用---四则数学表达式的求解 数学表达式的求解是栈的一个重要的应用,在计算机的应用中 如果求解一个四则运算表达式,我们可能会直接写一个程序例如什么printf("% ...
- 国产化设备鲲鹏CentOS7上源码安装Python3.7
具体编译过成与正常的Python源代码在x86平台上的过程无异,此篇随笔仅当用作复制黏贴的备忘录.不得不说在一个老旧系统上安装一个老旧的Python版本,从头编译一个Python还是一个较为稳健的选择 ...
- 尾递归与 memorize 优化
尾递归与 memorize 优化 本文写于 2020 年 12 月 10 日 递归 递归是一种非常常见的算法思维,在大家刚开始学编程的时候应该就会接触到. 我们可以这么理解递归: function 讲 ...
- cpulimit-限制CPU速率
CPULimit是一个简单的程序,它可以限制指定进程的CPU百分比. 1.安装依赖 root@localhost:~# apt-get -y install git 2.从GitHUB中克隆源码到本地 ...
- vision transformer
VIT 总览 Step1 Step2
- 互联网公司目标管理OKR和绩效考核的误区
最近看了一篇关于「谷歌放弃OKR,转向全新的GRAD系统」的文章,我转到了研发效能DevOps的微信群里,结果引起了大家热烈的讨论,正好我们也在使用 OKR,所以也来谈谈我的理解以及我们应用起来的实际 ...
- .NET Core 企业微信回调配置
1.配置API接收 2.下载加密解密库 地址:https://developer.work.weixin.qq.com/devtool/introduce?id=36388,也可以复制下面的代码 2. ...
- 【主流技术】ElasticSearch 在 Spring 项目中的实践
前言 ElasticSearch简称es,是一个开源的高扩展的分布式全文检索引擎. 它可以近乎实时的存储.检索数据,其扩展性很好,ElasticSearch是企业级应用中较为常见的技术. 下面和大家分 ...
- 使用Java编写一个日期时间封装类
package base; import java.util.GregorianCalendar; import java.util.StringTokenizer; import java.util ...