Java實現堆排序和計數排序
阿新 • • 發佈:2019-01-17
ret wap static 堆排序 變更 heapsort mil 葉子節點 source
堆排序代碼:
import java.util.Arrays; /** * 思路:首先要知道大頂堆和小頂堆,數組就是一個堆,每個i節點的左右孩子是2i+1和2i+2 * 有了堆,將其堆化:從(n/2)-1個元素開始向下修復,將每個節點修復為小(大)頂堆 * 修復完成後,數組具有小(大)頂堆的性質 * 按序輸出:小頂堆可以對數組逆序排序,每次交換堆頂和末尾元素,對堆頂進行向下修復,這樣次小元素又到堆頂了 * * 時間復雜度:堆化:一半的元素修復,修復是單分支的,所以整體堆化為nlgn/2 * 排序:n個元素都要取出,因此調整n次,每次調整修復同上是lgn的,整體為nlgn * 空間復雜度:不需要開辟輔助空間 * 原址排序 * 穩定性 **/ public class HeapSort { static void sort(int []A){ // 堆排序第一步: 先對A進行堆化 makeMinHeap(A); for(int x = A.length-1;x>=0;x--){ // 堆排序第二步: 把堆頂,0號元素和最後一個元素對調 swap(A, 0, x); // 堆排序第三步:縮小堆的範圍,對堆頂元素進行向下調整 MinHeapFixDown(A, 0, x); } }static void makeMinHeap(int[] A){ int n = A.length; for(int i = n/2-1;i>=0;i--){ MinHeapFixDown(A,i,n); } } private static void MinHeapFixDown(int[] A, int i, int n) { // 找到左右孩子 int left = 2 * i + 1; int right = 2 * i + 2 ;// 左孩子已經越界,i就是葉子節點 if (left>=n) { return ; } // min 指向了左右孩子中較小的那個 int min = left; if (right>=n) { min = left; }else { if (A[right]<A[left]) { min = right; } } // 如果A[i]比兩個孩子都要小,不用調整 if (A[i]<=A[min]) { return ; } // 否則,找到兩個孩子中較小的,和i交換 int temp = A[i]; A[i] = A[min]; A[min] = temp; // 小孩子那個位置的值發生了變化,i變更為小孩子那個位置,遞歸調整 MinHeapFixDown(A, min, n); } private static void swap(int[] A, int p, int bigger) { int temp = A[p]; A[p] = A[bigger]; A[bigger] = temp; } public static void main(String[] args) { int arr[] = new int[10]; for(int i=0;i<10;i++){ arr[i] = (int) ((Math.random()+1)*10); } System.out.println("排序前:"+Arrays.toString(arr)); sort(arr); System.out.println("排序後:"+Arrays.toString(arr)); } }
堆排序結果:
計數排序代碼:
import java.util.Arrays; /** * 計數排序 * 思路:開辟新的空間,空間大小為max(source)+1 * 掃描source,將value作為輔助空間的下標,用輔助空間的該位置元素記錄value的個數 * 如 9 7 5 3 1,helper的空間就為10 * 依次掃描,value為9,將helper[9]++,以此類推,完成之後,再去遍歷helper * 如果該位(index)的值為0,說明index不曾在source中出現 * 如果該位(index)的值為 1,說明出現了1次,為2說明出現了兩次 * 時間復雜度:掃描一次source,掃描一次helper,復雜度為N+K * 空間復雜度:如果source裏面有個元素較大的,那麽開辟的輔助空間較大 * 非原址排序 * 穩定性:相同元素不會出現交叉,非原址都是拷來拷去 * 如果要優化一下空間,可以求出minOf(source),那麽helper的長度為(max-min)+1,這樣就能短點 * 計數有缺陷,數據較為密集或範圍較小時,適用。 */ public class CountSort { static void sort(int []source){ int max = source[0]; for (int i = 1; i < source.length; i++) { if (source[i]>max) { max = source[i]; } } int []helper = new int[max+1]; for(int e:source){ helper[e]++; } int current = 0; // 數據回填的位置 for (int i = 1; i < helper.length; i++) { while(helper[i]>0){ source[current++] = i; helper[i]--; } } } // 保證排序穩定性的版本 public static void sort2(int[] source) { int max = source[0]; for (int i = 1; i < source.length; i++) { if (source[i]>max) { max = source[i]; } } int []helper = new int[max+1]; for (int e : source) { helper[e]++; } for (int i = 1; i < helper.length; i++) { helper[i] += helper[i - 1]; } int len = source.length; int[] target = new int[len]; for (int i = len - 1; i >= 0; i--) { target[helper[source[i]] - 1] = source[i]; helper[source[i]]--; } System.arraycopy(target, 0, source, 0, len); } public static void main(String[] args) { int arr[] = new int[10]; for(int i=0;i<10;i++){ arr[i] = (int) ((Math.random()+1)*10); } System.out.println("排序前:"+Arrays.toString(arr)); sort2(arr); System.out.println("排序後:"+Arrays.toString(arr)); } }
計數排序結果:
Java實現堆排序和計數排序