就是比如有1,4,3,5,2五个数组成的一个数组arr。冒泡排序就是索引0开始,arr[0]和arr[1]比较,1小于3,不动(1,4,3,5,2),然后arr[1]和arr[2]比较,4大于3,交换位置(1,3,4,5,2),此时arr[2]为4,然后arr[2]和arr[3]比较,4小于5,不动(1,3,4,5,2),然后arr[3]和arr[4]比较,5大于2,交换位置,此时arr[4]为5(1,3,4,2,5)。这样,一次冒泡就结束了
第一次冒泡能确定数组最后一个元素为最大的元素,以此类推,第二次冒泡能确定数组倒数第二个元素为倒数第二大的元素。(注意,第二次冒泡时,数值比较到arr.length-1就可以,因为最后一个元素已经最大,没有比较意义,后面也一样,每次冒泡少比较一个数)因此,需要进行arr.length-1次冒泡,就能排好序。
/**
* Description 冒泡排序学习演示
* date 2023/10/16 10:40
*
* @author zqh
* @since JDK 1.8
*/
public class BubbleSort {
public static void main(String[] args) {
int[] arr = new int[]{100,54,-324,2,1,1,98,1};
bubbleSort(arr);
for (int i : arr) {
System.out.print(" "+i);
}
}
/**
* Description 冒泡排序
* date 2023/10/16 10:40
*
* @param arr 需要排序的数组
* @author zqh
* @since JDK 1.8
*/
public static void bubbleSort(int[] arr){
// 冒泡次数
for (int i = 0;i<arr.length-1;i++){
// 冒泡比较次数,j代表每个索引
for (int j = 0;j<arr.length-1-i;j++){
// 比较过程
// 当前一个数大于后一个数的时候,交换位置
if (arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
}
冒泡次数如何确定? 当然不需要,所以添加一个boolean的标志标志数组是否有序 依旧是准备一个数组arr:1,3,-2,4,5 代码其实没太懂。。用debug看的才稍微明白点 看了眼JavaGuide上的代码,比这个好一点,贴一个 JavaGuide:https://javaguide.cn/cs-basics/algorithms/10-classical-sorting-algorithms.html#%E5%9B%BE%E8%A7%A3%E7%AE%97%E6%B3%95-1 准备数组int[] arr = new int[]{1,3,2,4,5} 代码参考的JavaGuide。 首先有一个增量的概念gap=length/2,缩小增量gap=gap/2…一直除以2 gap也可以理解成步长,普通插入排序步长为1,希尔排序步长为gap,假如gap=3。按照上面的例子就是,arr[0] 和arr[3] 插入排序 如果gap为2,就是arr[0] 和 arr[2] 和arr[4]插入排序
看数组有几个数,假如有五个,第一次确定最后一个元素,第二次确定倒数第二个元素…以此类推,确定了arr.length-1次(因为确定到第二个元素的时候就可以结束了,第一个元素一定最小)。
所以是i=0;i优化:如果数组一开始就有序,还需要排序吗?
/**
* Description 冒泡排序学习演示
* date 2023/10/16 10:40
*
* @author zqh
* @since JDK 1.8
*/
public class BubbleSort {
public static void main(String[] args) {
int[] arr = new int[]{100,54,-324,2,60,1,98,1};
bubbleSort(arr);
for (int i : arr) {
System.out.print(" "+i);
}
}
/**
* Description 冒泡排序
* date 2023/10/16 10:40
*
* @param arr 需要排序的数组
* @author zqh
* @since JDK 1.8
*/
public static void bubbleSort(int[] arr){
// 优化:如果没进if,证明没交换,数组已经有序
// 定义一个标志,默认为true,代表有序
boolean flag = true;
// 冒泡次数
for (int i = 0;i<arr.length-1;i++){
// 冒泡比较次数,j代表每个索引
for (int j = 0;j<arr.length-1-i;j++){
// 比较过程
// 当前一个数大于后一个数的时候,交换位置
// 进了if证明数组不有序,改标志为false
flag = false;
if (arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
if (flag) {
break;
}
}
}
}
选择排序
设置一个int变量min,由数组下标0开始初始化,每选择排序一次,就加一。
同时需要定义一个int变量min的index,在后面交换时用
那么启始的min为arr[0]=1。
然后用后面的数和这个min比较,3比1大,不变,-2比1小,那么他们俩交换(-2,3,1,4,5),此时min就等于-2了,然后后面的数就和-2比较,4大于-2,不变,5大于-2,不变。这一趟选择排序就比较完了(-2,3,1,4,5)。
第二次快排,初始化min的下标就为**(上一次min数组下标+1)**的0+1=1。此时min=arr[1]=3,min为3,后面的数就和3比较,步骤同上。
这样比较需要比较几次呢?当min=arr.length-1时,证明比较到了倒数第二个数,这次比较结束后,(数组下标0~倒数第二个数的下标)这个之间的数都是有序的了,剩下最后一个数就不用排了。所以选择排序次数为arr.length-1/**
* Description 选择排序学习
* date 2023/10/16 12:15
*
* @author zqh
* @since JDK 1.8
*/
public class SelectSort {
public static void main(String[] args) {
int[] arr = new int[]{100, 54, 60, 0, -324, 2, 60, 1, 98, 1};
selectSort(arr);
for (int i : arr) {
System.out.print(" " + i);
}
}
/**
* Description 选择排序
* date 2023/10/16 12:15
*
* @param arr 接收的数组
* @author zqh
* @since JDK 1.8
*/
public static void selectSort(int[] arr){
// 选择排序次数
for (int i = 0;i<arr.length-1;i++){
// 排序
// 定义min
int min = arr[i];
// 定义minindex
int minIndex = i;
// 开始比较,后面的数跟min比较,所以j+1
// 这个for是用来找出每次选择排序时的最小值和最小值的索引的
for (int j = i+1; j < arr.length; j++) {
if (min > arr[j]){
// 得到最小值
min = arr[j];
// 得到最小值的索引
minIndex = j;
}
}
// 实际交换数值的逻辑
// 能走到这里,证明一开始初始化的min不是最小值,然后通过上面的for循环,得到了min和minIndex
if (i!=minIndex){
// 互相交换
arr[minIndex] = arr[i];
arr[i] = min;
}
}
}
}
/**
* 选择排序
* @param arr
* @return arr
*/
public static int[] selectionSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
if (minIndex != i) {
int tmp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = tmp;
}
}
return arr;
}
插入排序
第一次插入排序,从arr[1]开始,arr[1]和arr[0]比较,如果arr[0]>arr[1],就交换位置。这样一次插入排序就完成了(1,3,2,4,5)。
第二次插入排序,关注arr[2],用arr[2]和arr[1]比较,2<3,那么2应该插在3前面,此时先别急着插,再用arr[2]和更前面的arr[0]比较,2>1,证明arr[2]不在arr[0]前面,这样就比较完了,注意要比较到arr[0]位置。此时(1,2,3,4,5)。
人话:从索引1开始,每次取一个索引+1的数a和前面的数排大小,插在合适的位置(左边小于a,右边大于a)
插入排序次数依旧是arr.length-1。public class InsertSort {
public static void main(String[] args) {
int[] arr = new int[]{5,4,9,6,5,3,6,7,4,1,2,8};
insertSort(arr);
for (int i : arr) {
System.out.print(" " + i);
}
}
public static void insertSort(int[] arr){
// 外层循环,循环次数
// 从第一个元素开始的话是i
希尔排序
这个增量有啥用?
假如有数组arr:1,5,6,7,9,2
gap=6/2=3。意思就是原数组要被分为3个数组,怎么分呢?根据gap,现在gap=3。就是每间隔3(gap)个元素成一组,arr[0] 和 arr[3] 一组,arr[1] 和 arr[4] 一组。
这样分好组之后,在不改变位置、索引的前提下组内排序,排好后如下:
1,5,2,7,9,6。然后gap=gap/2=1
每隔一个成一组,这时当做普通插入排序即可。
/**
* Description 希尔排序 JavaGuide 学习笔记
* date 2023/10/16 18:31
*
* @author zqh
* @since JDK 1.8
*/
public class ShellSort {
public static void main(String[] args) {
int[] arr = new int[]{100, 54, 60, 0, -324, 2, 60, 1, 98, 1};
shellSort(arr);
for (int i : arr) {
System.out.print(" " + i);
}
}
/**
* Description 希尔排序
* date 2023/10/16 18:39
*
* @param arr 待排序数组
* @author zqh
* @since JDK 1.8
*/
public static void shellSort(int[] arr){
// 定义初始步长
int gap = arr.length/2;
// 当步长大于0时,希尔排序
while (gap>0){
// 从gap位置比较,相当于插入排序中从第二个数开始
for (int i = gap; i < arr.length; i++) {
// 当前元素
int current = arr[i];
// 前一个元素的索引
int preIndex = i-gap;
// 插入排序
while (preIndex>=0 && current<arr[preIndex]){
// 交换之把大的放右边
arr[preIndex+gap] = arr[preIndex];
// 接着比较前面的数
preIndex = preIndex - gap;
}
// 交换之把小的放左边
arr[preIndex+gap] = current;
}
// gap/2
gap = gap/2;
}
}
}