本文講述時間複雜度爲n*logn的排序算法:歸併排序、快速排序、堆排序以及希爾排序的原理、Java實現以及變形應用。算法
1 public int[] mergeSort(int[] a, int n) 2 { 3 return doMergeSort(a, n, 0, n - 1); 4 } 5 public int[] doMergeSort(int[] a, int n, int start, int end) 6 { 7 int[] res = new int[n]; 8 if (n <= 1) 9 { 10 res[0] = a[start]; 11 return res; 12 } 13 // n>=2時,對其左右數組進行處理 14 int half = n / 2; 15 int leftEnd = start + half - 1; 16 int rightStart = leftEnd + 1; 17 //遞歸調用本函數,獲取有序的左數組以及右數組 18 int[] left = doMergeSort(a, half, start, leftEnd); 19 int[] right = doMergeSort(a, n - half, rightStart, end); 20 // 將左右序列合併 21 int k = 0, i = 0, j = 0; 22 while (i < half && j < n - half) 23 {//由前日後比較兩個序列,取較小值填充到res中,取值後該序列日後移動取下一個值比較 24 if (left[i] <= right[j]) 25 { 26 res[k++] = left[i++]; 27 } 28 else 29 { 30 res[k++] = right[j++]; 31 } 32 } 33 // 剩餘的直接放入 34 while (i < half) 35 { 36 res[k++] = left[i++]; 37 } 38 while (j < n - half) 39 { 40 res[k++] = right[j++]; 41 } 42 return res; 43 }
1 public int[] quickSort(int[] a, int n) 2 { 3 doQuickSort(a, n, 0, n - 1); 4 return a; 5 } 6 public void doQuickSort(int[] a, int n, int start, int end) 7 { 8 if (n > 1) 9 { 10 int current = a[end]; 11 int minLen = 0;// 小於區間的長度 12 int i = start; 13 for (; i < end; i++) 14 { 15 if (a[i] < current) 16 {//發現比當前數小的數,擴充小於區間 17 int temp = a[start + minLen]; 18 a[start + minLen] = a[i]; 19 a[i] = temp; 20 minLen++; 21 } 22 } 23 a[end] = a[start + minLen]; 24 a[start + minLen] = current; 25 //當前位置已經肯定,排左右序列 26 doQuickSort(a, minLen, start, start + minLen - 1); 27 doQuickSort(a, n - minLen - 1, start + minLen + 1, end); 28 } 29 }
變形應用:三色排序練習題shell
有一個只由0,1,2三種元素構成的整數數組,請使用交換、原地排序而不是使用計數進行排序。給定一個只含0,1,2的整數數組A及它的大小,請返回排序後的數組。保證數組大小小於等於500。
測試樣例:
[0,1,1,0,2,2],6 返回:[0,0,1,1,2,2] |
public int[] heapSort(int[] a, int n) { for (int len = n; len > 0; len--) {// len爲構建的堆的大小 for (int i = len / 2 - 1; i >= 0; i--) {// 從後往前遍歷非葉子節點 while (2 * i + 1 < len) { int j = 2 * i + 1;// 左節點序號 if (j + 1 < len && a[j] < a[j + 1]) { j++; } if (a[i] < a[j]) { int temp = a[j]; a[j] = a[i]; a[i] = temp; i = j; } else { break; } } } int temp = a[len - 1]; a[len - 1] = a[0]; a[0] = temp; } return a; }
已知一個幾乎有序的數組,幾乎有序是指,若是把數組排好順序的話,每一個元素移動的距離能夠不超過k,而且k相對於數組來講比較小。請選擇一個合適的排序算法針對這個數據進行排序。 給定一個int數組A,同時給定A的大小n和題意中的k,請返回排序後的數組。 數組 測試樣例: [2,1,4,3,6,5,8,7,10,9],10,2 函數 返回:[1,2,3,4,5,6,7,8,9,10] 測試 解析:維護一個大小爲k的小根堆,每次調整完這個小根堆後,最小值就會出如今第一位,此時移除第一位,添加後一位數進來,繼續調整這個小根堆便可。能夠想象爲一個從前日後移動的滑動窗口,滑動窗口中是一個小根堆。ui |
public int[] shellSort(int[] a, int n) { // 步長選擇 for (int k = 1, step = 10; step > 1; k++) { step = n / (2 * k); for (int i = step; i < n; i++) { if (a[i] < a[i - step]) { int temp = a[i]; a[i] = a[i - step]; a[i - step] = temp; int pre = i - step; while (pre - step > 0) { if (a[pre] < a[pre - step]) { temp = a[pre]; a[pre] = a[pre - step]; a[pre - step] = temp; pre -= step; } else { break; } } } } } return a; }