N個降序陣列,找到最大的K個數TOP K
阿新 • • 發佈:2019-01-23
轉載至:http://www.cnblogs.com/ywl925/p/3794852.html
假定有20個有序陣列,每個陣列有500個數字,降序排列,數字型別32位uint數值,現在需要取出這10000個數字中最大的500個,怎麼做?
解決方法
這裡其實有很多解決方法,笨拙的或者巧妙的。這裡介紹一個非常不錯的方法,使用最大堆堆排序:
1. 建立大頂堆,維度為陣列的個數,這裡為20(第一次 插入的是每個陣列中最大的值,即第一個元素)。
2. 刪除最大堆堆頂,儲存到陣列或者棧中,然後向最大堆插入刪除的元素所在陣列的下一個元素。
3. 重複第1,2個步驟,直到刪除個數為最大的K個數,這裡為500.
程式碼:
#include <iostream> #include<cstdlib> #include <algorithm> #include <queue> #include <functional> using namespace std; #define ROWS 20 #define COLS 500 int data[ROWS][COLS]; void CreateData() { for(int i=0; i<ROWS; i++) { for(int j=0; j<COLS;j++) { data[i][j] = rand(); //生成隨機元素 } } for( int i=0; i<ROWS; i++) sort(data[i],data[i]+COLS, greater<int>()); //對每一行降序排列 } struct Node { int *p; //指向某個列,因為要放入優先佇列中,所以要比較大小,就用結構體封裝了下 bool operator<(const struct Node &node) const { return *p < *node.p; } }; voidOutMinData( int k) { struct Node arr[ROWS]; for(int i=0; i<ROWS;i++) { arr[i].p = data[i]; //初始化指標指向各行的首位 } priority_queue<Node > queue( arr, arr+ROWS ); //使用優先佇列,預設是大堆 for( int i=0; i<k&&i<COLS; i++) //演算法核心就是這個迴圈 { Node temp = queue.top(); //取出佇列中最大的元素 cout << *temp.p << " " <<endl; queue.pop(); //從佇列裡刪除 temp.p++; //對應行的指標後移 queue.push( temp ); //這裡面有log(ROWS)次操作,所以演算法的總複雜度為O(klog(20)) } } int main() { CreateData(); //生成資料 int k=500; OutMinData( k ); //輸出k個元素,這裡k不要大於列數COL,可以改進,去掉這個限制,不過會讓程式不好懂,就沒加 return 0; }
題外話:
上面的是有序陣列,但是如果是無序陣列呢,可以建立維度為K(這裡為500)的最小堆,然後每次刪除最小堆的堆頂,直到遍歷完所有的數,剩下的就是所求的最大K個數。
我們向堆插入數值時,首先我們先在堆的尾部插入該值,然後再根據大小關係不斷的提升它的位置
刪除堆的最小值時,首先把堆的最後一個節點複製到根節點上,然後刪除最後一個節點。之後我們根據大小關係不斷和交換位置,使其滿足堆的定義。
堆的這兩種操作所用的時間,和樹的深度成正比。我們不難發現堆的時間複雜度為O(log n).