Java常用的八種排序演算法與程式碼實現(二):歸併排序法、快速排序法
注:這裡給出的程式碼方案都是通過遞迴完成的
---
歸併排序(Merge Sort):
分而治之,遞迴實現
如果需要排序一個數組,我們先把陣列從中間分成前後兩部分,然後對前後兩部分進行分別排序,再將排好序的數組合並在一起,這樣整個陣列就有序了
歸併排序是穩定的排序演算法,時間複雜度為O(nlogn),空間複雜度是O(n)
圖解:
程式碼:
/** * 歸併排序 * * @param arr 待排陣列 * @param low 歸併起始位置 * @param high 歸併截至位置 */ public static void mergeSort(int[] arr, int low, int high) { int mid = (low + high) / 2; if (low < high) { // 分開 mergeSort(arr, low, mid); mergeSort(arr, mid + 1, high); // 合併 mergeArray(arr, low, mid, high); } } private static void mergeArray(int[] arr, int low, int mid, int high) { int[] temp = new int[high - low + 1]; // 陣列被分成兩部分,進行合併 // 兩個陣列中的元素進行比較,小的進入temp中 int i = low; int k = 0; int j = mid + 1; while (i <= mid && j <= high) { if (arr[i] <= arr[j]) { temp[k++] = arr[i++]; } else { temp[k++] = arr[j++]; } } while (i <= mid) { temp[k++] = arr[i++]; } while (j <= high) { temp[k++] = arr[j++]; } // 將temp陣列中的資料,重新灌入被排序陣列,此時陣列順序已經排好 for (int l = 0; l < temp.length; l++) { arr[low + l] = temp[l]; } }
注:
空間複雜度又稱漸進空間複雜度,指的是隨資料量的增加,額外需要使用的空間開銷。前一次歸併後的陣列空間,可以被接下來的操作使用。所以該排序的空間複雜度是O(n)
---
快速排序(QuockSort):
如果需要排序陣列中下標從p到r之間的一組資料,我們會選擇從p到r之間的任意一個數據作為區分點,我們遍歷p到r之間的資料,將小於區分點的資料放左邊,大於區分點的資料放右邊,然後將區分點放到中間
快速排序是一種原地排序,不穩定的排序,時間複雜度為O(nlogn),空間複雜度是O(n)
圖解:
程式碼:
/** * 快速排序 * * @param arr 待排陣列 * @param low 排序起始位置 * @param high 排序終止位置 */ public static void quockSort(int[] arr, int low, int high) { if (low > high) { return; } int i = low; int j = high; int pivot = arr[low]; while (i < j) { // 如果選取兩端的數作為pivot,那麼迴圈要從基數的對面開始,選取中間的基數則不需要考慮這個問題 while (i < j && arr[j] > pivot) { j--; } while (i < j && arr[i] <= pivot) { i++; } if (i < j) { int c = arr[i]; arr[i] = arr[j]; arr[j] = c; } } int p = arr[i]; arr[i] = arr[low]; arr[low] = p; quockSort(arr, low, i - 1); quockSort(arr, i + 1, high); }
---
測試方法及生成隨機陣列方法:
/** * 生成一個長度5-10的隨機陣列 * * @return 隨機陣列 */ private static int[] initArray() { int len = 5 + new Random().nextInt(6); int[] arr = new int[len]; for (int i = 0; i < arr.length; i++) { arr[i] = new Random().nextInt(100); } return arr; } public static void main(String[] args) { int[] arr2 = initArray(); System.out.println("排序之前的陣列是:" + Arrays.toString(arr2)); quockSort(arr2,0,arr2.length-1); System.out.println("排序之後的陣列是:" + Arrays.toString(arr2)); }
---
關於 如果選取兩端的數作為pivot,那麼迴圈要從基數的對面開始 的參考部落格:
https://blog.csdn.net/w282529350/article/details/50982650
---
測試結果,親測有效:
歸併:
排序之前的陣列是:[71, 79, 11, 20, 68, 78, 95]
排序之後的陣列是:[11, 20, 68, 71, 78, 79, 95]
快速:
排序之前的陣列是:[44, 25, 17, 44, 71, 25, 66, 96, 36]
排序之後的陣列是:[17, 25, 25, 36, 44, 44, 66, 71, 96]