package com.zjl.tool.sort; /** * 求前面的最大K個 解決方案:小根堆 (數據量比較大(特別是大到內存不能夠容納)時,偏向於採用堆) * @author 張恩備 * @date 2016-11-25 下午12:15:36 */ public class TopNByHeap { /** * 待排序列(R1,R2,...,Rk,...Rn)看做是徹底二叉樹,經過比較、交換,父節點和孩子節點的值, * 使得對於任意元素Rk(k<=n/2),知足Rk>=R(2k),Rk>=R(2k+1) * @param arr 數組對象 * @param start 數組的開始下標 * @param end 數組的結束下標 */ private static void HeapAdjust(int[] arr, int start, int end) { //當下標爲start的元素有孩子元素時 while(start <= end/2) { //left和right分別爲左右孩子元素的下標,max爲左右孩子中值較小的孩子的元素下標 int left = 2 * start+1; int right = 2 * start+2; int min = 0; //若是既有左孩子,又有右孩子 if(left < end&&right <= end) { //若是左孩子小於右孩子的值,max = right,不然爲max = left if(arr[left] <= arr[right]) min = left; else min = right; } //若是隻有左孩子,沒有右孩子,max值爲left if(left <= end&&right > end) { min = left; } //若是沒有孩子,則代表到了徹底二叉樹的葉子節點 if(left > end) { break; } //若是當前節點值小於兩孩子中的值較大者,那麼將當前節點值與max交換 if(arr[start] > arr[min]){ int tmp = arr[start]; arr[start] = arr[min]; arr[min] = tmp; } //當前節點向孩子節點迭代 start = min; } } /** * 建立k個節點的小根堆 * * @param a * @param k * @return */ static int[] createHeap(int a[], int k) { int[] result = new int[k]; for (int i = 0; i < k; i++) { result[i] = a[i]; } //由最後一個非葉子節點,向根節點迭代,建立最大堆,數組中的最大值將被移動到根節點 for(int start = k-1/2;start >= 0;start--) { HeapAdjust(result, start, k-1); } return result; } static void insert(int a[], int value, int k) { //當輸入元素的值value大於堆的根元素值時,則將堆的根元素的值賦值爲輸入元素的值value a[0]=value; //將改變後的堆從新k個節點的生成小根堆 for(int start = k-1/2;start >= 0;start--) { HeapAdjust(a, start, k-1); } } static int[] getTopKByHeap(int input[], int k) { int heap[] = createHeap(input, k); for(int i=k;i<input.length;i++){ //當input[i]值大於堆的根元素值時,將input[i]插入到堆中 if(input[i]>heap[0]){ insert(heap, input[i], k); } } //將小根堆降序排列 while(k-1 > 0){ //交換arr[0]和arr[k-1]的值 int tmp = heap[0]; heap[0] = heap[k-1]; heap[k-1] = tmp; //待排序堆的範圍變爲依次減少,最後剩下一個元素時結束 //執行完這一步,根元素的值變爲整個待序列中的最小值 HeapAdjust(heap, 0, k-2); k--; } return heap; } public static void main(String[] args) { int a[] = {40,55,49,73,12,27,98,81,64,36,78}; //獲取top3 int result[] = getTopKByHeap(a, 3); for (int temp : result) { System.out.print(temp + " "); } } }