基礎排序演算法 java 實現(冒泡、選擇、插入、快排、歸併、堆排)
阿新 • • 發佈:2019-01-26
package demo; import java.util.Arrays; public class SortUtil { private static void printArr(int[] arr) { System.out.println(Arrays.toString(arr)); } private static void checkSort(int[] arr) { for (int i = 0; i < arr.length - 1; i++) { if (arr[i] > arr[i + 1]) { throw new RuntimeException("Sort Error!"); } } } private static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } // 本機測試 public static void main(String[] args) { // int[] arr = {4, 3, 5}; int[] arr = new int[50000 * 100]; java.util.Random random = new java.util.Random(); for (int i = 0; i < arr.length; i++) { arr[i] = random.nextInt(arr.length); } // System.out.println("排序前:"); // printArr(arr); long s = System.currentTimeMillis(); // bubbleSort(arr);// 50000 資料 5000+ ms // selectSort(arr);// 50000 資料 1700+ ms // insertSort(arr);// 50000 資料 360+ ms quickSort(arr, 0, arr.length - 1);// 50000 * 100 資料 770 ms // mergeSort(arr);// 50000 * 100 資料 1300 ms // mergeSort(arr, 0, arr.length - 1);// 50000 * 100 資料 1300 ms // heapSort(arr);// 50000 * 100 資料 1650 ms long e = System.currentTimeMillis(); System.out.println("耗時:" + (e - s)); checkSort(arr); System.out.println("排序正確!"); // System.out.println("排序後:"); // printArr(arr); } private static void bubbleSort(int[] arr) { int len = arr.length; for (int i = 0; i < len - 1; i++) { //要放置正確元素的目標位置,最後一個不用放 for (int j = len - 1; j > i; j--) { // 從後往前,把最小(大)的挪動到目標位置 if (arr[j] < arr[j - 1]) { // 後面的大於前面 swap(arr, j, j - 1);//如果沒有傳送互動則表示排序已經完成,但會多n次判斷 } } } } private static void selectSort(int[] arr) { int len = arr.length; for (int i = 0; i < len - 1; i++) { //要放置正確元素的目標位置,最後一個不用放 int min = i; for (int j = i + 1; j < len; j++) { if (arr[j] < arr[min]) { // 後面的大於前面 min = j; } } swap(arr, i, min); } } private static void insertSort(int[] arr) { for (int i = 1; i < arr.length; i++) {// 第一個不需要插入排序 int temp = arr[i]; int j = i - 1; while (j >= 0 && temp < arr[j]) { arr[j + 1] = arr[j]; j--; } arr[j + 1] = temp; } } /*** quick ***/ private static void quickSort(int[] arr, int left, int right) { if (left >= right) return; int pivotIndex = partition(arr, left, right); quickSort(arr, left, pivotIndex - 1);//排序 target 前面的 quickSort(arr, pivotIndex + 1, right);//排序 target 後面的 } private static int partition(int[] arr, int left, int right) { int pivot = arr[right];//堆排序是原地排序,這個額外空間可以省去的,這裡為了語義明確在此宣告 int target = left; for (int i = left; i < right; i++) { if (arr[i] < pivot) { swap(arr, target++, i); } } swap(arr, target, right);// target 已經處在正確的位置 return target; } /*** merge:遞迴實現 從外向裡 ***/ private static void mergeSort(int[] arr, int left, int right) { if (left == right) return;//待排序列長度為1 int middle = (left + right) / 2; mergeSort(arr, left, middle); mergeSort(arr, middle + 1, right); merge(arr, left, middle, right); } /*** merge:迭代實現 從裡向外 ***/ private static void mergeSort(int[] arr) { int len = arr.length; int left;//需要歸併的左座標 int middle;//需要歸併的中座標(定義為左側的結束端座標),也就是步長的最後一個 int right;//需要歸併的右座標 for (int mergeLen = 1; mergeLen < len; mergeLen *= 2) { left = 0; while (left + mergeLen < len) { // 有後面的陣列需要歸併 middle = left + mergeLen - 1; right = middle + mergeLen < len ? middle + mergeLen : len - 1; merge(arr, left, middle, right); left = right + 1; } } } private static void merge(int[] arr, int left, int leftEnd, int right) { int len = right - left + 1; int[] temp = new int[len];//輔助空間 int tempIndex = 0;//輔助空間指標 int i = left;//左側指標 int j = leftEnd + 1;//右側指標 while (i <= leftEnd && j <= right) { if (arr[i] <= arr[j]) {// 帶等號保證歸併排序的穩定性 temp[tempIndex++] = arr[i++]; } else { temp[tempIndex++] = arr[j++]; } } while (i <= leftEnd) { temp[tempIndex++] = arr[i++];//左側陣列未 } while (j <= right) { temp[tempIndex++] = arr[j++]; } for (int k = 0; k < len; k++) { arr[left + k] = temp[k];//將輔助空間內容替換至真實陣列的 left-right 空間 } } /*** heap ***/ private static void heapSort(int[] arr) { buildHeap(arr);//初始化大頂堆 int maxHeapIndex = arr.length - 1; while (maxHeapIndex > 0) {// 堆(無序區)元素個數大於1,未完成排序 swap(arr, 0, maxHeapIndex--);// 此處交換操作很有可能把後面元素的穩定性打亂,所以堆排序是不穩定的排序演算法 adjustHeap(arr, 0, maxHeapIndex);// 從新的堆頂元素開始向下進行堆調整,時間複雜度O(logn) } } private static void buildHeap(int[] arr) { // 建堆,時間複雜度O(n) int len = arr.length; for (int i = len / 2 - 1; i >= 0; i--) {//從最後一個非葉子節點開始,向上調堆,當i==0時,所有堆成為最大堆 adjustHeap(arr, i, len - 1); } } private static void adjustHeap(int[] arr, int i, int maxIndex) { int leftChild = i * 2 + 1; int rightChild = i * 2 + 2; int max = i; if (leftChild <= maxIndex && (arr[leftChild] > arr[max])) { max = leftChild; } if (rightChild <= maxIndex && (arr[rightChild] > arr[max])) { max = rightChild; } if (max != i) { swap(arr, i, max);//把最大的換到當前堆頂,然後繼續調劑被破壞的子堆 adjustHeap(arr, max, maxIndex);// 保證被破壞的子堆繼續維持大頂堆性質 } } }