Comparisonjava
算法在計算機上所佔用的存儲空間,包括存儲算法自己所佔用的存儲空間、算法的輸入輸出數據所佔用的存儲空間和算法在運行過程當中臨時佔用的存儲空間這三個方面。node
但在評估一個算法的優良性的時候,前兩個基本是固定的,只有算法運行是臨時佔用的存儲空間纔會隨着數據量的增大而有較大影響。所以,通常以程序運行時佔用的臨時存儲大小做爲評估指標。算法
快速排序 (Divide and Conquer)api
1 public void quickSort(int[] arr, int l, int r) { 2 if (l < r) { 3 int p = partition(arr, l, r); // divide and conquer 4 quickSort(arr, l, p - 1); 5 quickSort(arr, p + 1, r); 6 } 7 } 8 9 // select the first element as pivot 10 // use do while loop 11 public int partition(int[] arr, int l, int r) { 12 int i, j, pivot, tmp; 13 pivot = arr[l]; 14 i = l; 15 j = r + 1; 16 17 do { 18 for (i++; i < r && arr[i] <= pivot; i++) ;// do while loop, less than or equal to pivot 19 for (j--; j > l && arr[j] > pivot; j--) ;// do while loop, greater than pivot 20 21 // swap arr i,j 22 tmp = arr[i]; 23 arr[i] = arr[j]; 24 arr[j] = tmp; 25 } while (i < j); 26 if (i > j) { // cross line, swap back 27 tmp = arr[i]; 28 arr[i] = arr[j]; 29 arr[j] = tmp; 30 } 31 32 arr[l] = arr[j]; // place the pivot to appropriate position 33 arr[j] = pivot; 34 35 return j; 36 }
Best: O(nlogn); Worst: O(n^2) Average: O(nlogn) 1.38nlogn數組
歸併排序 (Divide and Conquer)app
1 void mergeSort(int[] arr, int l, int r) { 2 if (l < r) { 3 int m = l + (r - l) / 2; 4 mergeSort(arr, l, m); // divide and conquer 5 mergeSort(arr, m + 1, r); 6 merge(arr, l, m, r); 7 } 8 } 9 10 void merge(int[] arr, int l, int m, int r) { 11 int i, j, k, n1, n2; 12 n1 = m - l + 1; // size of the left part arr 13 n2 = r - m; // size of the right part arr 14 15 int[] L = new int[n1]; // tmp arrays 16 int[] R = new int[n2]; 17 18 // copy elements to the tmp arrays 19 for (i = 0; i < n1; i++) { 20 L[i] = arr[l + i]; 21 } 22 for (j = 0; j < n2; j++) { 23 R[j] = arr[m + 1 + j]; 24 } 25 26 i = j = 0; 27 k = l; // point at the beginning position 28 29 // Copy smaller elements back to arr (overwrite) 30 while (i < n1 && j < n2) { 31 if (L[i] <= R[j]) { 32 arr[k++] = L[i++]; 33 } else { 34 arr[k++] = R[j++]; 35 } 36 } 37 38 // copy the remaining elements 39 while (i < n1) { 40 arr[k++] = L[i++]; 41 } 42 while (j < n2) { 43 arr[k++] = R[j++]; 44 } 45 }
always: O(nlogn)less
堆排序 From wikipedia (Transform and Conquer)ide
注意,建堆過程可能與代碼中不太同樣,代碼中數組已存在,圖示中是逐漸插入過程。函數
基本思想: 工具
建立堆(-->maxHeapify) --> 反覆的調用del_max()
函數獲取最大值
排序具體過程:
shift_down(0)
,目的是把新的數組頂端數據調整到相應位置1 public class HeapSort { 2 private static int[] sort = new int[]{1,0,10,20,3,5,6,4,9,8,12,17,34,11}; 3 public static void main(String[] args) { 4 buildMaxHeapify(sort); // build a max heap 5 heapSort(sort); // sort the array 6 print(sort); 7 } 8 9 private static void buildMaxHeapify(int[] data){ 10 //沒有子節點的才須要建立最大堆,從最後一個的父節點開始 11 int startIndex = getParentIndex(data.length - 1); 12 //從尾端開始建立最大堆,每次都是正確的堆 13 for (int i = startIndex; i >= 0; i--) { 14 maxHeapify(data, data.length, i); 15 } 16 } 17 18 /** 19 * 建立最大堆 20 * @param data 21 * @param heapSize須要建立最大堆的大小,通常在sort的時候用到,由於最多值放在末尾,末尾就再也不納入最大堆了 22 * @param index當前須要建立最大堆的位置 23 */ 24 private static void maxHeapify(int[] data, int heapSize, int index){ 25 // 當前點與左右子節點比較 26 int left = getChildLeftIndex(index); 27 int right = getChildRightIndex(index); 28 29 int largest = index; 30 if (left < heapSize && data[index] < data[left]) { 31 largest = left; 32 } 33 if (right < heapSize && data[largest] < data[right]) { 34 largest = right; 35 } 36 //獲得最大值後可能須要交換,若是交換了,其子節點可能就不是最大堆了,須要從新調整 37 if (largest != index) { 38 int temp = data[index]; 39 data[index] = data[largest]; 40 data[largest] = temp; 41 maxHeapify(data, heapSize, largest); // recursive to the root node 42 } 43 } 44 45 /** 46 * 排序,最大值放在末尾,data雖然是最大堆,在排序後就成了遞增的 47 * @param data 48 */ 49 private static void heapSort(int[] data) { 50 //末尾與頭交換,交換後調整最大堆 51 for (int i = data.length - 1; i > 0; i--) { // i--, ignore the last one element for length i 52 int temp = data[0]; 53 data[0] = data[i]; // put it to the end 54 data[i] = temp; 55 maxHeapify(data, i, 0); 56 } 57 } 58 59 /** 60 * 父節點位置 61 * @param current 62 * @return 63 */ 64 private static int getParentIndex(int current){ 65 return (current - 1) >> 1; // shift one bit to the right, equals to (current -1) / 2 66 } 67 68 /** 69 * 左子節點position注意括號,加法優先級更高 70 * @param current 71 * @return 72 */ 73 private static int getChildLeftIndex(int current){ 74 return (current << 1) + 1; 75 } 76 77 /** 78 * 右子節點position 79 * @param current 80 * @return 81 */ 82 private static int getChildRightIndex(int current){ 83 return (current << 1) + 2; 84 } 85 86 private static void print(int[] data){ 87 int pre = -2; 88 for (int i = 0; i < data.length; i++) { 89 if (pre < (int)getLog(i+1)) { 90 pre = (int)getLog(i+1); 91 System.out.println(); 92 } 93 System.out.print(data[i] + " |"); 94 } 95 } 96 97 /** 98 * 以2爲底的對數 99 * @param param 100 * @return 101 */ 102 private static double getLog(double param){ 103 return Math.log(param)/Math.log(2); 104 } 105 }
avg: O(nlogn) <= 2nlogn 在隨機文件上時間測試的結果顯示heapsort比快速排序要慢,可是能夠比得上mergeSort. (來源於算法設計與分析基礎 2rd Edition P228)
選擇排序
1 void selectSort(int[] arr){ 2 int min; 3 for(int i = 0;i<arr.length-1;i++){ 4 min = i; 5 for(int j=i;j<arr.length;j++){ 6 if(arr[min] > arr[j]){ // find the smallest elements 7 min = j; 8 } 9 } 10 int tmp = arr[min]; 11 arr[min] = arr[i]; 12 arr[i] = tmp; 13 } 14 }
Best: O(n^2); Worst: O(n^2) Average: O(n^2)
冒泡排序
void bubbleSort(int[] arr){ for(int i=0;i<arr.length;i++){ for(int j = arr.length-1; j > i; j--){ if(arr[j] < arr[j-1]){ // find the smallest through bubble int tmp = arr[j]; arr[j] = arr[j-1]; arr[j-1] = tmp; } } } }
Best: O(n^2); Worst: O(n^2) Average: O(n^2)
此代碼實現的最佳時間消耗 O(n^2), 若要使最佳狀況時間開銷達到O(n),能夠設置一個sentinel實現:當不發生交換的時候就break退出,完成了排序。
插入排序
1 void insertSort(int[] arr) { 2 if (arr.length < 2) { 3 return; 4 } 5 6 int i, j; 7 int temp; 8 for (i = 1; i < arr.length; i++) { 9 temp = arr[i]; 10 for (j = i - 1; j >= 0 && arr[j] > temp; j--) { // in-place 11 arr[j + 1] = arr[j]; // shift 12 } 13 arr[j + 1] = temp; 14 } 15 }
Best: O(n); Worst: O(n^2) Average: O(n^2)
Java工具類排序
java.util.Arrays.sort(arr);
計算Java程序運行時間:
1 long startTime = System.nanoTime(); 2 //code 3 long endTime = System.nanoTime(); 4 System.out.println("Took "+(endTime - startTime) + " ns");
Test It:
1 public static void main(String[] args) { 2 int arr[] = {1, 3, 1, 8, 4, 8,3,23,2}; 3 Main main = new Main(); 4 long startTime = System.nanoTime(); 5 // main.quickSort(arr, 0, arr.length - 1); 6 // main.selectSort(arr); 7 // main.insertSort(arr); 8 // main.bubbleSort(arr); 9 10 //code 11 long endTime = System.nanoTime(); 12 System.out.println("Took "+(endTime - startTime) + " ns"); 13 for (int a : arr) { 14 System.out.println(a); 15 } 16 }