五十道程式設計小題目 --- 28 八大排序演算法 java 之 02希爾排序
阿新 • • 發佈:2019-01-04
2. 插入排序—希爾排序(Shell`s Sort)
希爾排序是1959 年由D.L.Shell 提出來的,相對直接排序有較大的改進。希爾排序又叫縮小增量排序
基本思想:
先將整個待排序的記錄序列分割成為若干子序列分別進行直接插入排序,待整個序列中的記錄“基本有序”時,再對全體記錄進行依次直接插入排序。
操作方法:
- 選擇一個增量序列t1,t2,…,tk,其中ti>tj,tk=1;
- 按增量序列個數k,對序列進行k 趟排序;
- 每趟排序,根據對應的增量ti,將待排序列分割成若干長度為m 的子序列,分別對各子表進行直接插入排序。僅增量因子為1 時,整個序列作為一個表來處理,表長度即為整個序列的長度。
希爾排序的示例:
演算法實現:
我們簡單處理增量序列:增量序列d = {n/2 ,n/4, n/8 .....1} n為要排序數的個數
即:先將要排序的一組記錄按某個增量d(n/2,n為要排序數的個數)分成若干組子序列,每組中記錄的下標相差d.對每組中全部元素進行直接插入排序,然後再用一個較小的增量(d/2)對它進行分組,在每組中再進行直接插入排序。繼續不斷縮小增量直至為1,最後使用直接插入排序完成排序。
[java] view plain copy print?- import java.util.Random;
- publicclass ShellSort {
-
//希爾排序
- publicstaticint[] shellSort(int[] arr){
- /*//確定增量序列
- double n = arr.length;
- int[] d = new int[(int)n]; //增量序列
- for(int i=0; i<n; i++){
- if(n > 0){
- d[i] = (int) Math.ceil(n/2);
- n = (int) Math.ceil(n/2);
-
if( n <= 3 ){
- d[i+1] = 1;
- break;
- }
- }
- }
- System.out.println("增量序列:");
- print(d);*/
- double n = arr.length; //n 定義為double很重要。如果是int ,這(int)Math.ceil(5/2)==2。如果是double,(int)Math.ceil(5/2)==3
- for(int i=(int)Math.ceil(n/2) ; i>0 ; i=(int)Math.ceil(n/2) ){ //增量序列:
- if( i==2 && n%2 != 0){ //如果是n=5時,下一個增量應該是3,在下一個增量應該是1,去除2,
- n=i; //但是, 如果是n=4時,下一個增量應該是2, 此時增量為2 ,應該被保留
- continue;
- }
- for(int j=0; j<n ;j++ ){ //趟數,趟數與增量相同
- int k = j;
- while(k+i<arr.length){ //分組,將arr 分組為相隔i的幾組,然後一個一個比較
- if ( arr[k] > arr[k + i]) {
- int tmp = arr[k];
- arr[k] = arr[k + i];
- arr[k + i] = tmp;
- }
- k = k+i;
- }
- }
- n = i;
- System.out.print("增量為" + i + "時,排序為 : ");
- print(arr);
- if(n==1){ // 因為double n=1,時 (int)Math.ceil(n/2)==1,如果不寫break,這裡會一直迴圈
- break;
- }
- }
- return arr;
- }
- // 列印陣列
- publicstaticvoid print(int[] arr) {
- for (int i = 0; i < arr.length; i++) {
- System.out.print(arr[i] + " ");
- }
- System.out.println();
- }
- publicstaticvoid main(String[] args) {
- int[] arr2 = {49,38,65,97,76,13,27,49,55,04};
- System.out.println("排序前 : ");
- print(arr2);
- System.out.println("排序後 : ");
- print(shellSort(arr2));
- //測試:
- System.out.println();
- System.out.println("任意陣列測試:");
- Random r = new Random();
- int[] testArr = newint[20];
- for (int i = 0; i < 20; i++) {
- testArr[i] = r.nextInt(100);
- }
- System.out.println("排序前 : ");
- print(testArr);
- System.out.println("排序後 : ");
- print(shellSort(testArr));
- }
- }
輸出結果: [java] view plain copy print?
- 排序前 :
- 4938659776132749554
- 排序後 :
- 增量為5時,排序為 : 1327495544938659776
- 增量為3時,排序為 : 1344938274955659776
- 增量為1時,排序為 : 4132738494955657697
- 4132738494955657697
- 任意陣列測試:
- 排序前 :
- 385793049274583887614531658772120405594
- 排序後 :
- 增量為10時,排序為 : 145393049212040557638571658772745838894
- 增量為5時,排序為 : 142093049214516557627534058773857838894
- 增量為3時,排序為 : 142093016214027533849554557777658838894
- 增量為1時,排序為 : 149162021273038404945535557587677838894
-
149162021