小頂堆與topK的具體程式碼實現《演算法很美》

羅彬樺發表於2020-12-21

題9:前k個數

  • 求海量資料(正整數)按逆序排列的前k個數(topK),因為資料量太大,不能全部儲存在記憶體中,只能一個一個地從磁碟或者網路上讀取資料,請設計一個高效的演算法來解決這個問題
  • 第一行:使用者輸入K,代表要求得topK
  • 隨後的N(不限制)行,每一行是一個整數代表使用者輸入的資料
  • 使用者輸入-1代表輸入終止
  • 請輸出topK,從小到大,空格分割
  • 解決:
    大頂堆
public class 前k個數 {

  static int[] heap;
  static int size = 0;
  static int k;

  public static void main(String[] args){
      Scanner sc = new Scanner(System.in);
      int k = sc.nextInt();
      heap = new int[k];
      int x = sc.nextInt();
      while(x!=-1){
         deal(x);//處理x
         x = sc.nextInt();
      }
      printRs();
  }

  private static void printRs(){
     Util.print(heap);
  }

  /**
   * 如果資料量小於等於k,直接加入堆中
   * 等於k的時候,進行堆化
  */
  private static void deal(int x){
     if (index<k){
       heap[index++] = x;
       if(index==k){
        //堆化
        makeMinHeap(heap);
     }
    }else
     //x和堆頂進行比較,如果x大於堆頂,x將堆頂擠掉並向下調整
     if(heap[0]<x){
        heap[0]=x;
        MinHeapFixDown(heap, 0,k);
        printRs();
     }
  }
  static void makeMinHeap(int[] A){
     int n = A.length;
     for (int i= n/2-1;i>=0;i--){
       MinHeapFixDown(A,i,n);
     }
  }
    static void MinHeapFixDown(int[] A,int i,int n){
        // 找到左邊孩子
        int left = 2*i+1;
        int right = 2*i+2;
        //左孩子已經越界,i就是葉子節點
        if(left>=n){
            return;
        }
        int min = left;
        if(right>=n){
            min = left;
        }else{
            if(A[right]<A[left]){
                min = right;
            }
        }
        //min指向了左右孩子中較小的那個

        //如果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);
    }
//    public static void sortDesc(int[] arr){
//        makeMinHeap(arr); //1.建立小頂堆
//        int length = arr.length;
//        for (int i = length-1; i>= 1; i--){
//            Util.swap(arr,i,0);//堆頂(最小)元素換到元素末尾,末尾元素到了堆頂
//            MinHeapFixDown(arr,0,i); //調整堆頂,邊界遞減
//        }
//    }

    static void sort(int[] A){
        //先對A進行堆化
        makeMinHeap(A);
        for(int x = A.length-1;x>=0;x--){
            //把堆頂,0號元素和最後一個元素對調
            Util.swap(A,0,x);
            //縮小堆的範圍,堆堆頂元素進行向下調整
            MinHeapFixDown(A,0,x);
        }
    }

}

相關文章