N個降序數組,找到最大的K個數TOP K

轉載至: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;
    }
};

void OutMinData( 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).

發佈了9 篇原創文章 · 獲贊 13 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章