八大排序算法
1, 算法的基本概念
程序=数据结构+算法
算法中先学习排序算法
排序也成为排序算法(sort algorithm), 是将一组数据按照指定的顺序进行排列的过程
2, 八大排序算法基础
2.1, 排序算法分类
内部排序和外部排序
- 内部排序:将所有的需要处理的数据都加载到内存中进行排序处理
- 外部排序:数据量大或者其他原因, 无法把数据全部加载到内存中, 需要借助外部存储进行排序
2.2, 时间复杂度
- 时间复杂度其实是渐进时间复杂度的简称,是指计算时间的一个趋势的复杂度
T(n)=n²+7n+6 与 T(n)=3n²+2n+2 : 时间复杂度都是:O(n²)。
用常数1代替运行时间中的所有加法常数 T(n)=n²+7n+6 => T(n)=n²+7n+1
修改后的运行次数函数中,只保留最高阶项 T(n)=n²+7n+1 => T(n) = n²
去除最高阶项的系数 T(n) = n² => T(n) = n² => O(n²)
-
常数阶O(1)
int i=0; int j = 1; i++; j++; int m = i+j;
-
对数阶O(log2n)
说明:在while循环里面,每次都将 i 乘以 2,乘完之后,i 距离 n 就越来越近了。假设循环x次之后,i 就大于 2 了,此时这个循环就退出了,也就是说 2 的 x 次方等于 n,那么 x = log2n也就是说当循环 log2n 次以后,这个代码就结束了。因此这个代码的时间复杂度为:O(log2n) 。 O(log2n) 的这个2 时间上是根据代码变化的,i = i * 3 ,则是 O(log3n) .
int i=1; while(i<n) { i = i*2; }
-
线性阶O(n)
说明:这段代码,for循环里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变化的,因此这类代码都可以用O(n)来表示它的时间复杂度
for(int i=0;i<n;i++){ j = i; j++; }
-
线性对数阶O(nlog2n)
说明:线性对数阶O(nlogN) 其实非常容易理解,将时间复杂度为O(logn)的代码循环N遍的话,那么它的时间复杂度就是 n * O(logN),也就是了O(nlogN)
for(m=1;m<n;m++) { i=1; while(i<n) { i=i*2; } }
-
平方阶O(n2)
说明:平方阶O(n²) 就更容易理解了,如果把 O(n) 的代码再嵌套循环一遍,它的时间复杂度就是 O(n²),这段代码其实就是嵌套了2层n循环,它的时间复杂度就是 O(nn),即 O(n²) 如果将其中一层循环的n改成m,那它的时间复杂度就变成了 O(mn)
for(int i=0;i<n;i++) { for (int j=0;j<n;j++){ **** } }
-
立方阶O(n3)
for(int i=0;i<n;i++) {
for (int j=0;j<n;j++){
for (int m=0;m<n;m++){
****
}
}
}
- k次方阶O(nk) : 这里k>3
- 指数阶O(2n)
说明:
常见的算法时间复杂度由小到大依次为:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)< Ο(nk) <Ο(2n) ,随着问题规模n的不断增大,上述时间复杂度不断增大,算法的执行效率越低
从图中可见,我们应该尽可能避免使用指数阶的算法
2.3, 平均时间复杂度和最坏时间复杂度
平均时间复杂度是指所有可能的输入实例均以等概率出现的情况下,该算法的运行时间。
最坏情况下的时间复杂度称最坏时间复杂度。一般讨论的时间复杂度均是最坏情况下的时间复杂度。 这样做的原因是:最坏情况下的时间复杂度是算法在任何输入实例上运行时间的界限,这就保证了算法的运行时间不会比最坏情况更长。
平均时间复杂度和最坏时间复杂度是否一致,和算法有关(如图:)。
2.4, 八大排序算法
1, 冒泡算法
相邻的两个进行比较,如果前者比后者大,那么就把大的移动到后面。
第一轮把最大的移动到最后一位
第二位把次大的移动到倒数第二位
依次进行,直到有序(n个数最大进行n-1轮即可有序)
a06_01_Bubble_basic
package im.bool.a06_sort_algrithm;
/**
* #Author : ivanl001
* #Date : 2020/2/24 9:53 AM
* #Desc : 排序算法之冒泡推算过程:
* 这个过程中有一个优化过程:如果经过一轮冒泡,顺序完全没有变动,那么后续就不需要进行了,因为这个时候顺序已经排好了
**/
public class a06_01_Bubble_basic {
public static void main(String[] args) {
int[] nums = {3, 9, -1, -2, 10};
int temp;
System.out.println("第一次冒泡:");
for (int i=0;i<nums.length-1;i++) {
if (nums[i] > nums[i+1]) {
temp = nums[i];
nums[i] = nums[i + 1];
nums[i+1] = temp;
}
}
for (int i = 0; i < nums.length; i++) {
System.out.print(nums[i] + ", ");
}
System.out.println();
System.out.println("第二次冒泡:");
for (int i=0;i<nums.length-1-1;i++) {
if (nums[i] > nums[i+1]) {
temp = nums[i];
nums[i] = nums[i + 1];
nums[i+1] = temp;
}
}
for (int i = 0; i < nums.length; i++) {
System.out.print(nums[i] + ", ");
}
System.out.println();
System.out.println("第三次冒泡:");
for (int i=0;i<nums.length-1-2;i++) {
if (nums[i] > nums[i+1]) {
temp = nums[i];
nums[i] = nums[i + 1];
nums[i+1] = temp;
}
}
for (int i = 0; i < nums.length; i++) {
System.out.print(nums[i] + ", ");
}
System.out.println();
System.out.println("第四次冒泡");
for (int i=0;i<nums.length-1-3;i++) {
if (nums[i] > nums[i+1]) {
temp = nums[i];
nums[i] = nums[i + 1];
nums[i+1] = temp;
}
}
for (int i = 0; i < nums.length; i++) {
System.out.print(nums[i] + ", ");
}
System.out.println();
}
}
a06_02_Bubble
package im.bool.a06_sort_algrithm;
import jdk.internal.org.objectweb.asm.tree.FrameNode;
import java.util.Arrays;
/**
* #Author : ivanl001
* #Date : 2020/2/24 5:58 PM
* #Desc : 冒泡排序算法:两次循环实现
**/
public class a06_02_Bubble {
public static void main(String[] args) {
/*int[] nums = {9, -2, -1, 3, 10, 100, -3, 3, 4, 20};
bubbleSort(nums);
for (int j = 0; j < nums.length; j++) {
System.out.print(nums[j] + ", ");
}
System.out.println();*/
int[] nums = new int[80000];
for (int i = 0; i < 80000; i++) {
nums[i] = (int) (Math.random() * 80000);
}
// System.out.println(Arrays.toString(nums));
long startTime = System.currentTimeMillis();
bubbleSort(nums);
long endTime = System.currentTimeMillis();
//9s左右
System.out.println(endTime-startTime);
}
public static void bubbleSort(int[] nums) {
int temp;
boolean isOrdered = false;
//因为冒泡排序算法是两层循环,所以冒泡排序算法的时间复杂度是O(n^2)
for (int i = 0; i < nums.length-1; i++) {
isOrdered = true;
// System.out.println("第" + (i+1) + "次冒泡:");
//-------------------冒泡算法的精华代码--------------------
for (int j = 0; j < nums.length - 1 - i; j++) {
if (nums[j] > nums[j + 1]) {
temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
isOrdered = false;
}
}
/*for (int j = 0; j < nums.length; j++) {
System.out.print(nums[j] + ", ");
}
System.out.println();*/
//这个地方是一个小优化。如果经过一轮,数据顺序完全没有变动
if (isOrdered) {
System.out.println("第" + (i+1) + "次循环");
System.out.println("已经有序。。。");
break;
}
}
}
}
a06_03
- 如果是向左冒泡,那么左边的边界需要依次变大
- 如果是向右冒泡, 那么右边的边界需要依次变小
// 如果是向左冒泡,那么左边的边界需要依次变大
public static void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = arr.length-1; j > i; j--) {
if (arr[j] < arr[j - 1]) {
int temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
}
}
// 如果是向右冒泡, 那么右边的边界需要依次变小
public static void bubbleSort_v1(int[] arr){
for (int i = 0; i < arr.length; i++) {
// 注意:这里j < arr.length-i-1, 是减去i哈
for (int j = 0; j < arr.length-i-1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j + 1] = temp;
}
}
}
}
2, 快速排序(平分移动+迭代排序)-冒泡算法的优化
快速排序思路
首先以中间一个数字为基准,把该数右侧大于该数的移至该数左侧,把该数左侧大于数的移至该数右侧。这样大于该数的数字都在右侧,小于该数的都在该数左侧。
接着再使用迭代算法, 依次对左侧的进行相同方法的移动。
接着再使用迭代算法, 依次对右侧的进行相同方法的移动。
当迭代结束,该数组数字即是有序
a06_09_Quick
package im.bool.a06_sort_algrithm;
import java.util.Arrays;
/**
* #Author : ivanl001
* #Date : 2020/2/27 7:22 PM
* #Desc : 快速排序法,这个是冒泡排序算法的优化。和冒泡算法属于同一排序算法
* 快排的话, 在n值比较大的时候就比shell要好很多。
* 如果都在8万数据的话, shell大概21ms,快排大概67ms
* 如果是8000万数据, shell大概41s,快排只需要12s
**/
public class a06_09_Quick {
public static void main(String[] args) {
/*int[] nums = {-9, 78, 0, 23, -567, 70};
quickSort(nums, 0, nums.length - 1);
System.out.println(Arrays.toString(nums));*/
int[] nums = new int[80000];
for (int i = 0; i < 80000; i++) {
nums[i] = (int) (Math.random() * 80000);
}
long startTime = System.currentTimeMillis();
quickSort(nums, 0, nums.length-1);
long endTime = System.currentTimeMillis();
//这里用了21ms左右, shell排序如果用前面的交换,大概5s, 插入排序1s左右, 冒泡大概9s,选择大概2s
//所以移位法速度提升简直是非常非常大的
System.out.println(endTime-startTime);
//System.out.println(Arrays.toString(nums));
}
public static void quickSort(int[] arr, int left, int right) {
int l = left;
int r = right;
// 中间值
int pivot = arr[(left + right) / 2];
int temp = 0;
while (l < r) {
// 这里在中轴左边左边从头开始找,直到找到比中轴大或相等的值
// 最后会找到中轴或者中轴右一位
while (arr[l] < pivot) {
l += 1;
}
// 这里在中轴右侧从尾部往前找, 直到找到比中轴小或相等的值
// 最后会找到中轴或者中轴左一位
while (arr[r] > pivot) {
r -= 1;
}
// 当r<l的时候, 说明已经把两边的值已经挪动完成。
// 相等的时候也可以跳出
if (l >= r) {
break;
}
// 交换
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
// 这两步必不可少。因为如果当前的值和中轴值一样,那么这个地方要跳过,要不然就是死循环,因为交换后,值不变,然后继续交换,继续相等
if (arr[l] == pivot) {
r--;
}
if (arr[r] == pivot) {
l++;
}
}
// 这个地方如果不添加,会死循环,因为跳不出来
if (l == r) {
l += 1;
r -= 1;
}
// 走完前面的说明比中间值小或相等的都会挪到左边, 比中间值大或相等的都会挪到右边.
if (left < r) {
quickSort(arr, left, r);
}
if (right > l) {
quickSort(arr, l, right);
}
}
}
3, 选择排序
大体思路:
第一轮从数组中选取最小的数据,放在第一位。
第二轮从第一个之后的那些数中选择最小的,放在第二位
第三轮从第二个之后的那些数中选取最小的,放在第三位
直至放到倒数第二位为止。
n个数字经过(n-1)轮后,即可保证有序
a06_03_Select_basic
package im.bool.a06_sort_algrithm;
import java.util.Arrays;
/**
* #Author : ivanl001
* #Date : 2020/2/24 7:57 PM
* #Desc : 选择排序基础: 这里是第一轮从第二个数开始,如果发现比第一个数小,先标记为最小,然后往后看,直到最后,那么把第一个数和标记的最小数互换
* 第二轮从第三个数开始,如果发现比第一个数小,先标记为最小,然后往后看,直到最后,那么把第二个数和标记的最小数互换
* 依次下去,直至最后一个数字
**/
public class a06_03_Select_basic {
public static void main(String[] args) {
int[] nums = {3, 9, -1, -2, -10};
int min = nums[0];
int index = 0;
//第一轮
min = nums[0];
index = 0;
for (int i = 0 + 1; i < nums.length; i++) {
if (min > nums[i]) {
min = nums[i];
index = i;
}
}
if (index > 0) {
nums[index] = nums[0];
nums[0] = min;
}
System.out.println(Arrays.toString(nums));
//第二轮
min = nums[1];
index = 1;
for (int i = 1 + 1; i < nums.length; i++) {
if (min > nums[i]) {
min = nums[i];
index = i;
}
}
if (index > 1) {
nums[index] = nums[1];
nums[1] = min;
}
System.out.println(Arrays.toString(nums));
//第三轮
min = nums[2];
index = 2;
for (int i = 2 + 1; i < nums.length; i++) {
if (min > nums[i]) {
min = nums[i];
index = i;
}
}
if (index > 2) {
nums[index] = nums[2];
nums[2] = min;
}
System.out.println(Arrays.toString(nums));
//第四轮
min = nums[3];
index = 3;
for (int i = 3 + 1; i < nums.length; i++) {
if (min > nums[i]) {
min = nums[i];
index = i;
}
}
if (index > 3) {
nums[index] = nums[3];
nums[3] = min;
}
System.out.println(Arrays.toString(nums));
}
}
a06_04_Select
package im.bool.a06_sort_algrithm;
import java.util.Arrays;
/**
* #Author : ivanl001
* #Date : 2020/2/24 8:31 PM
* #Desc : TODO
**/
public class a06_04_Select {
public static void main(String[] args) {
/*int[] nums = {3, 9, -1, -2, -10, 30, -5, 100, 30, 3, -4, 33};
selectSort(nums);
System.out.println(Arrays.toString(nums));*/
int[] nums = new int[80000];
for (int i = 0; i < 80000; i++) {
nums[i] = (int) (Math.random() * 80000);
}
long startTime = System.currentTimeMillis();
selectSort(nums);
long endTime = System.currentTimeMillis();
//2s左右, 比冒泡算法要快不少
System.out.println(endTime-startTime);
System.out.println(Arrays.toString(nums));
}
public static void selectSort(int[] nums) {
int min;
int index;
//因为有两轮循环,所以选择排序的时间复杂度是时间复杂度是O(n^2)
for (int i = 0; i < nums.length - 1; i++) {
// System.out.println("iiii");
min = nums[i];
index = i;
for (int j = i + 1; j < nums.length; j++) {
if (min > nums[j]) {
min = nums[j];
index = j;
}
}
if (index > i) {
nums[index] = nums[i];
nums[i] = min;
}
}
}
}
4, 插入排序
1,第一轮把第二个数和第一个比较, 如果比第一个小, 那么把第一个后移一位,然后把第二个数赋值到第一位上
2,第二轮把第三个数和第二个数比较,如果比第二个小,那么把第二个数后移一位,然后再和第一个数比较,如果还比第一个数小(否则把第三个数赋值到第二位上),再把第一个数后移一位,把第三个数赋值到第一位上。
3,依次执行如上逻辑
4,n个数字经过(n-1)轮插入,即可保证有序注意:插入是先在前面的数据中找到应该插入的位置,最后才会插入
这个和冒泡有点类似, 不过冒泡是先替换,然后再冒泡。插入时先找到最后位置,最后再替换。
插入的重点是: 把后面的一次往后移动一位,空出需要插入的,然后插入即可
a06_05_Insert_basic
package im.bool.a06_sort_algrithm;
import java.util.Arrays;
/**
* #Author : ivanl001
* #Date : 2020/2/25 9:24 AM
* #Desc : 插入排序算法的推导过程
**/
public class a06_05_Insert_basic {
public static void main(String[] args) {
int[] nums = {3, 9, -1, -2, 10};
//插入排序思路:
/**
* 1,第一轮把第二个数和第一个比较, 如果比第一个小, 那么把第一个后移一位,然后把第二个数赋值到第一位上
* 2,第二轮把第三个数和第二个数比较,如果比第二个小,那么把第二个数后移一位,然后再和第一个数比较,如果还比第一个数小(否则把第三个数赋值到第二位上),再把第一个数后移一位,把第三个数赋值到第一位上。
* 3,依次执行如上逻辑
* 4,n个数字经过(n-1)轮插入,即可保证有序
*/
//即将被插入的数字
int insertValue = nums[1];
//这个是要找的待插入序号
int indexToInsert = 1 - 1;
while (indexToInsert >= 0 && insertValue < nums[indexToInsert]) {
//如果有比待插入数据要大的, 那么就把该数据后移一位
nums[indexToInsert + 1] = nums[indexToInsert];
indexToInsert--;
}
nums[indexToInsert+1] = insertValue;
System.out.println(indexToInsert);
System.out.println("第一轮:" + Arrays.toString(nums));
//即将被插入的数字
insertValue = nums[2];
//这个是要找的待插入序号
indexToInsert = 2 - 1;
while (indexToInsert >= 0 && insertValue < nums[indexToInsert]) {
//如果有比待插入数据要大的, 那么就把该数据后移一位
nums[indexToInsert + 1] = nums[indexToInsert];
//因为这里先减,后循环,所以后面出了循环需要再加1加回来
indexToInsert--;
}
nums[indexToInsert+1] = insertValue;
System.out.println(indexToInsert);
System.out.println("第二轮:" + Arrays.toString(nums));
//即将被插入的数字
insertValue = nums[3];
//这个是要找的待插入序号
indexToInsert = 3 - 1;
while (indexToInsert >= 0 && insertValue < nums[indexToInsert]) {
//如果有比待插入数据要大的, 那么就把该数据后移一位
nums[indexToInsert + 1] = nums[indexToInsert];
//因为这里先减,后循环,所以后面出了循环需要再加1加回来
indexToInsert--;
}
nums[indexToInsert+1] = insertValue;
System.out.println(indexToInsert);
System.out.println("第三轮:" + Arrays.toString(nums));
//即将被插入的数字
insertValue = nums[4];
//这个是要找的待插入序号
indexToInsert = 4 - 1;
while (indexToInsert >= 0 && insertValue < nums[indexToInsert]) {
//如果有比待插入数据要大的, 那么就把该数据后移一位
nums[indexToInsert + 1] = nums[indexToInsert];
//因为这里先减,后循环,所以后面出了循环需要再加1加回来
indexToInsert--;
}
nums[indexToInsert+1] = insertValue;
System.out.println(indexToInsert);
System.out.println("第四轮:" + Arrays.toString(nums));
}
}
a06_06_Insert
package im.bool.a06_sort_algrithm;
import java.util.Arrays;
/**
* #Author : ivanl001
* #Date : 2020/2/25 10:11 AM
* #Desc : 插入排序法
**/
public class a06_06_Insert {
public static void main(String[] args) {
/*int[] nums = {3, 9, -1, -2, 10, -3, 0};
insert(nums);
System.out.println(Arrays.toString(nums));*/
int[] nums = new int[80000];
for (int i = 0; i < 80000; i++) {
nums[i] = (int) (Math.random() * 80000);
}
long startTime = System.currentTimeMillis();
insert(nums);
long endTime = System.currentTimeMillis();
//1s左右, 冒泡大概9s,选择大概2s,还是插入排序算法速度最快。
System.out.println(endTime-startTime);
//System.out.println(Arrays.toString(nums));
}
public static void insert(int[] nums) {
for (int i=1; i<nums.length; i++) {
//即将被插入的数字
int insertValue = nums[i];
//这个是要找的待插入序号
int indexToInsert = i - 1;
while (indexToInsert >= 0 && insertValue < nums[indexToInsert]) {
//如果有比待插入数据要大的, 那么就把该数据后移一位
nums[indexToInsert + 1] = nums[indexToInsert];
indexToInsert--;
}
//这个地方可以做个判断,如果相同,那本来就是在正确的位置
if (indexToInsert + 1 != i) {
nums[indexToInsert+1] = insertValue;
}
/*System.out.println(indexToInsert);
System.out.println("第" + i + "轮:" + Arrays.toString(nums));*/
}
}
}
5, shell(希尔)排序-插入排序的优化
shell排序是插入排序的优化,以减少数据插入之前为了找到插入位置而可能后移次数过多的问题
shell排序的时候有两种方式:
1,交换法。直接进行交换, 速度慢
2,移动法,先移动,而不是直接交换。速度快,超级快!80万只需要20ms左右。
下面图中有点说的好像不对:分组之后排序的时候, 用的应该不是插入排序,而是冒泡排序吧
不过有点需要留意:
shell排序的时候循环次数比插入排序循环次数要多,只不过shell排序的插入次数少了, 所以才快的
这个时间复杂度是n*logn,相对n的平方还是要小的
a06_08_Shell_01_exchange(并不是shell排序)
package im.bool.a06_sort_algrithm;
import java.util.Arrays;
/**
* #Author : ivanl001
* #Date : 2020/2/25 11:55 AM
* #Desc : 希尔排序-插入排序的优化算法: 直接交换,其实不是很好,效率有限
* 希尔排序的时间复杂度是nlogn,比n^2要好一些
**/
public class a06_08_Shell_01_exchange {
public static void main(String[] args) {
int[] nums = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
shellSort(nums);
/*int[] nums = new int[80000];
for (int i = 0; i < 80000; i++) {
nums[i] = (int) (Math.random() * 80000);
}
long startTime = System.currentTimeMillis();
shellSort(nums);
long endTime = System.currentTimeMillis();
//这里用了5s左右, 插入排序1s左右, 冒泡大概9s,选择大概2s,还是插入排序算法速度最快。
//这里本来是插入排序的优化,之所以比插入还要慢, 是因为这里直接更换,而插入是先移动,最后才替换。所以我们这里后续需要再优化一下,
//把交换改成先移动,最后再更换
System.out.println(endTime-startTime);*/
System.out.println(Arrays.toString(nums));
}
public static void shellSort(int[] nums) {
//插入排序的过程中,因为需要数据后移,在最差的情况下,每次数据都需要后移, 这种效率是不高的
//所以就有了希尔排序
int temp = 0;
int m=0;
for (int gap = nums.length / 2; gap > 0; gap /= 2) {
//第一轮排序,将10个数据分成了5组
for (int i = gap; i < nums.length; i++) {
for (int j = i - gap; j >= 0; j -= gap) {
if (nums[j] > nums[j + gap]) {
nums[j] = nums[j + gap];
nums[j + gap] = temp;
}
}
}
//System.out.println("第 " + (m++) + " 轮:" + Arrays.toString(nums));
}
}
}
a06_08_Shell_02_move
package im.bool.a06_sort_algrithm;
import sun.plugin2.ipc.windows.WindowsIPCFactory;
import java.util.Arrays;
/**
* #Author : ivanl001
* #Date : 2020/2/25 11:55 AM
* #Desc : 希尔排序-插入排序的优化算法: 采用希尔排序移动法
**/
public class a06_08_Shell_02_move {
public static void main(String[] args) {
/*int[] nums = {12, -10, 100, 8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
shellSort01(nums);
System.out.println(Arrays.toString(nums));*/
int[] nums = new int[80000];
for (int i = 0; i < 80000; i++) {
nums[i] = (int) (Math.random() * 80000);
}
long startTime = System.currentTimeMillis();
shellSort01(nums);
long endTime = System.currentTimeMillis();
//这里用了21ms左右, shell排序如果用前面的交换,大概5s, 插入排序1s左右, 冒泡大概9s,选择大概2s
//所以移位法速度提升简直是非常非常大的
System.out.println(endTime-startTime);
//System.out.println(Arrays.toString(nums));
}
public static void shellSort01(int[] nums) {
//插入排序的过程中,因为需要数据后移,在最差的情况下,每次数据都需要后移, 这种效率是不高的
//所以就有了希尔排序
//int temp = 0;
int m = 0;
for (int gap = nums.length / 2; gap > 0; gap /= 2) {
//第一轮排序,将10个数据分成了5组
for (int i = gap; i < nums.length; i++) {
int j = i;
int temp = nums[j];
//教程中这里多判断了一个条件, 个人感觉不是很必要,所以直接舍弃了
//下面的移动过程可以参考插入算法
while ((j - gap >= 0) && temp < nums[j - gap]) {
//先把小的移动到后面
nums[j] = nums[j - gap];
j -= gap;
}
nums[j] = temp;
}
//System.out.println("第 " + (m++) + " 轮:" + Arrays.toString(nums));
}
}
}