程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 5.查找最小的k個元素[Kmin]

5.查找最小的k個元素[Kmin]

編輯:C++入門知識

【題目】

輸入n個整數,輸出其中最小的k個。

例如輸入1,2,3,4,5,6,7和8這8個數字,則最小的4個數字為1,2,3和4。

【分析】

這道題最簡單的思路莫過於把輸入的n個整數排序,這樣排在最前面的k個數就是最小的k個數。只是這種思路的時間復雜度為O(nlogn)。我們試著尋找更快的解決思路。

我們可以先創建一個大小為k的數據容器來存儲最小的k個數字。接下來我們每次從輸入的n個整數中讀入一個數。如果容器中已有的數字少於k個,則直接把這次讀入的整數放入容器之中;如果容器中已有k個數字了,也就是容器已滿,此時我們不能再插入新的數字而只能替換已有的數字。我們找出這已有的k個數中最大值,然和拿這次待插入的整數和這個最大值進行比較。如果待插入的值比當前已有的最大值小,則用這個數替換替換當前已有的最大值;如果帶插入的值比當前已有的最大值還要大,那麼這個數不可能是最小的k個整數之一,因為我們容器內已經有k個數字比它小了,於是我們可以拋棄這個整數。

因此當容器滿了之後,我們要做三件事情:一是在k個整數中找到最大數,二是有可能在這個容器中刪除最大數,三是可能要插入一個新的數字,並保證k個整數依然是排序的。如果我們用一個二叉樹來實現這個數據容器,那麼我們能在O(logk)時間內實現這三步操作。因此對於n個輸入數字而言,總的時間效率就是O(nlogk)。

我們可以選擇用不同的二叉樹來實現這個數據容器。由於我們每次都需要找到k個整數中的最大數字,我們很容易想到用最大堆。在最大堆中,根結點的值總是大於它的子樹中任意結點的值。於是我們每次可以在O(1)得到已有的k個數字中的最大值,但需要O(logk)時間完成刪除以及插入操作。

我們自己從頭實現一個最大堆需要一定的代碼。我們還可以采用紅黑樹來實現我們的容器。紅黑樹通過把結點分為紅、黑兩種顏色並根據一些規則確保樹是平衡的,從而保證在紅黑樹中查找、刪除和插入操作都只需要O(logk)。在STL中set和multiset都是基於紅黑樹實現的。如果面試官不反對我們用STL中的數據容器,我們就直接拿過來用吧。下面是基於STL中的multiset的參考代碼:

時間復雜度:

數組存儲K個元素:K+(N-K)*(K+1) =O(nk)

堆存儲K個元素:K+(N-K)*(2*lgK+1)=O(nlgk)

【代碼】

 C++ Code  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42  
typedef multiset<int, greater<int> >  IntHeap;

///////////////////////////////////////////////////////////////////////
// find k least numbers in a vector
///////////////////////////////////////////////////////////////////////
void FindKLeastNumbers
(
    const vector<int> &data,               // a vector of data
    IntHeap &leastNumbers,                 // k least numbers, output
    unsigned int k
)
{
    leastNumbers.clear();

    if(k == 0 || data.size() < k)
        return;

    vector<int>::const_iterator iter = data.begin();
    for(; iter != data.end(); ++ iter)
    {
        // if less than k numbers was inserted into leastNumbers
        if((leastNumbers.size()) < k)
            leastNumbers.insert(*iter);

        // leastNumbers contains k numbers and it's full now
        else
        {
            // first number in leastNumbers is the greatest one
            IntHeap::iterator iterMax = leastNumbers.begin();

            // if is less than the previous greatest number
            if(*iter < *iterMax)
            {
                // replace the previous greatest number
                leastNumbers.erase(*iterMax);
                leastNumbers.insert(*iter);
            }
        }
    }
}

【參考】

http://zhedahht.blog.163.com/blog/static/2541117420072432136859/

http://blog.csdn.net/liangbopirates/article/details/9377105

http://blog.csdn.net/v_JULY_v/article/details/6370650

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved