希爾排序(更高效的插入排序)
減少最小數在最后一位的情況下要循環的次數
思路:
把數組按增量(n/2)分組,對每一組使用插入排序去排序交換位置,然后不停地增量/2,直到其為1時,結束
- 分組:如n/2=5
891723
8與3為一組
從不包含本身的數開始數 - 兩種實現方法:
交換法(效率較低)
移動法(效率較高)
交換法
對第一輪排序的分析
public class ShellSort {public static void main(String[] args) {int[] arr = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};System.out.println("排序前---");System.out.println(Arrays.toString(arr));shellSort(arr);}public static void shellSort(int[] arr) {//第一種方式:交換法//10個數據進行了三輪排序//第一輪,將1o個數據分成了5組//遍歷每一組,共有5組for (int i = 5; i < arr.length; i++) {//遍歷各組中所有的元素(共有5組),每一組有兩個元素,步長5//int j = i-5剛好是每一組的第一個元素//j -= 5為了退出當前循環,進行下一組交換for (int j = i - 5; j >= 0; j -= 5) {//如果當前元素大于加上步長后的元素,說明需要交換if (arr[j] > arr[j + 5]) {//交換int temp = arr[j];arr[j] = arr[j + 5];arr[j + 5] = temp;}}}System.out.println("第1輪插入后---");System.out.println(Arrays.toString(arr));}
}
排序過程
排序前---
[8, 9, 1, 7, 2, 3, 5, 4, 6, 0]
第1輪插入后---
[3, 5, 1, 6, 0, 8, 9, 4, 7, 2]
第2輪插入后---
[0, 2, 1, 4, 3, 5, 7, 6, 9, 8]
第3輪插入后---
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
代碼實現:
public class ShellSort {public static void main(String[] args) {int[] arr = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};System.out.println("排序前---");System.out.println(Arrays.toString(arr));shellSort(arr);}public static void shellSort(int[] arr) {//第一種方式:交換法//10個數據進行了三輪排序//第一輪,將1o個數據分成了5組//遍歷每一組,共有5組//gsp每一次的增量,最后為1int count = 0;for (int gsp = arr.length / 2; gsp > 0; gsp /= 2) {for (int i = gsp; i < arr.length; i++) {//遍歷各組中所有的元素(共有5組),每一組有兩個元素,步長5//int j = i-5剛好是每一組的第一個元素//j -= 5為了退出當前循環,進行下一組交換for (int j = i - gsp; j >= 0; j -= gsp) {//如果當前元素大于加上步長后的元素,說明需要交換if (arr[j] > arr[j + gsp]) {//交換int temp = arr[j];arr[j] = arr[j + gsp];arr[j + gsp] = temp;}}}System.out.println("第" + (++count) + "輪插入后---");System.out.println(Arrays.toString(arr));}}
}
移動法
交換法效率低是因為發現一個就交換一個
public class ShellSort {public static void main(String[] args) {int[] arr = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};System.out.println("排序前---");System.out.println(Arrays.toString(arr));shellSort2(arr);}public static void shellSort2(int[] arr) {//第二種方法:移動法//使用增量,逐步縮小增量int count = 0;for (int gap=arr.length/2;gap>0;gap/=2){//從第gap個元素開始,逐個對其所在組進行直接插入排序//遍歷每一個組for (int i = gap; i < arr.length; i++) {int index=i;//待插入的下標,每個組的第二個元素int value=arr[index];//用臨時變量記錄要插入的數//找位置arr[index-gap]每個組第一個元素if(arr[index]<arr[index-gap]){while (index-gap>=0&&value<arr[index-gap]){//移動arr[index]=arr[index-gap];index-=gap;}//當退出while就找到了插入的位置arr[index]=value;}}System.out.println("第" + (++count) + "輪插入后---");System.out.println(Arrays.toString(arr));}}}
無注釋版
public class TestShellSort {public static void main(String[] args) {int[] arr = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};System.out.println("排序前---");System.out.println(Arrays.toString(arr));shellSort2(arr);}private static void shellSort1(int[] arr) {//交換法for (int gap = arr.length / 2; gap > 0; gap /= 2) {for (int i = gap; i < arr.length; i++) {for (int j = i - gap; j >= 0; j -= gap) {if (arr[j] > arr[j + gap]) {int temp = arr[j];arr[j] = arr[j + gap];arr[j + gap] = temp;}}}}System.out.println("排序后---");System.out.println(Arrays.toString(arr));}private static void shellSort2(int[] arr) {
//移動法for (int gap = arr.length / 2; gap > 0; gap /= 2) {for (int i = gap; i < arr.length; i++) {int index=i;int value=arr[index];if (arr[index]<arr[index-gap]){while (index-gap>=0&&value<arr[index-gap]){arr[index]=arr[index-gap];index-=gap;}arr[index]=value;}}}System.out.println("排序后---");System.out.println(Arrays.toString(arr));}
}