Top K問題與多路歸併排序

2021-09-24 09:27:22 字數 2174 閱讀 8326

pro1:尋找前k大數

方法1:k小根堆  後面的值若大於當前根,則替換之,並調整堆

大部分人都推薦的做法是用堆,小根堆。下面具體解釋下:

如果k = 1,那麼什麼都不需要做,直接遍歷一遍,時間複雜度o(n)。

下面討論k 比較大的情況,比如1萬。

建立乙個小根堆,則根是當前最小的第k個數。然後讀入n-k個數,每次讀入乙個數就與當前的根進行比較,如果大於當前根,則替換之,並調整堆。如果小,則讀入下乙個。

時間複雜度o(n*logk)。

方法2:利用快排分割槽思想:

本題還有乙個時間複雜度比較好的做法。在程式設計之美上提到過該演算法。

首先找到最大的第k個數。這個時間複雜度可以做到o(n),具體做法如下(利用快排分割槽思想):

從n個數中隨機選擇乙個數,掃瞄一遍,比n大的放在右邊,r個元素,比n小的放左邊,l個元素

如果:  a:l = k-1   返回n

b:l > k-1 在l個元素中繼續執行前面的操作。

c:l < k-1  在r個元素中繼續執行前面的操作。

b,c每次只需執行一項,因此平均複雜度大概為:o(n+n/2+n/4...)=o(2n)=o(n)

pro2: k路合併求top-k

20路已經有序,20路合併  求top500

有 20 個陣列,每個陣列有 500 個元素,並且是有序排列好的,現在在這 20*500個數中找出排名前 500 的數。

答:從20個陣列中各取乙個數,並記錄每個數的**陣列,建立乙個含20個元素的大根堆。此時堆頂就是最大的數,取出堆頂元素,並從堆頂元素的**陣列中取下乙個數加入堆,再取最大值,一直這樣進行500次即可。

pro3: k路合併排序

請給出乙個時間為o(nlgk)、用來將k個已排序鍊錶合併為乙個排序鍊錶的演算法,此處n為所有輸入鍊錶中元素的總數。

演算法思想:

1. 從k個鍊錶中取出每個鍊錶的第乙個元素,組成乙個大小為k的陣列arr,然後將陣列arr轉換為最小堆,那麼arr[0]就為最小元素了;

2. 取出arr[0],將其放到新的鍊錶中,然後將arr[0]元素在原煉表中的下乙個元素補到arr[0]處,即arr[0].next,如果 arr[0].next為空,即它所在的鍊錶的元素已經取完了,那麼將堆的最後乙個元素補到arr[0]處,堆的大小自動減1,迴圈即可。

pro4: 整體有序區域性無序問題

乙個有100億個元素的整型陣列,它的元素是有序的,現在把它分成若干段,每段不超過20個元素,每段的元素個數不等,現在在每段內將這些元素的順序打亂,然後重新將這100億個元素的陣列排序,請問時間複雜度最小的演算法是什麼?並給出時間複雜度。

分析:如果每段長度相等,則可以考慮採用上面的k路歸併,但此處長度不相等,需另行考慮其它方法。

解:(直接插入排序)

假設第1到第5n個數已經有序為sort(5n),那麼我們要將5n+1到5n+5這5個資料新增到已排序的陣列中,只需要進行插入排序,將這5個數新增進即可。由於分段的長度不超過5,所以第5n+1個數在插入的時候,最多隻需要搜尋到第5n-4個數就可以了,比較個數不會超過5次。又因為5n+1到5n+5是已經排好序的,所以,後面的數比較次數也不會超過5次(最多比較到前乙個插入的位置)。因此,每加入5個數到已排序陣列中,時間複雜度是o(5*5),

假設長度為n,每段長不超過k。則每段插入的時間複雜度即為o(k*k)。

而對於以段為單位插入的操作,需要進行n/k次,所以,總的時間複雜度是o(k*k)*o(n/k)=o(nk)

pro5:100億個數,求最大的1萬個數,並說出演算法的時間複雜度

建乙個堆,先把最開始的1萬個數放進去。以後每進乙個,都把最小的趕出來。

上述演算法的可選實現工具:自己建立陣列進行堆排序、使用優先佇列priority_queue、使用集合set multiset

在最大堆中,根結點的值總是大於它的子樹中任意結點的值。於是我們每次可以在o(1)得到已有的k個數字中的最大值18,但需要o(logk)時間完成刪除以及插入操作。

佇列(queue)維護了一組物件,進入佇列的物件被放置在尾部,下乙個被取出的元素則取自佇列的首部。priority_queue特別之處在於,允許使用者為佇列中儲存的元素設定優先順序。這種佇列不是直接將新元素放置在佇列尾部,而是放在比它優先順序低的元素前面。優先佇列有兩種,一種是最大優先佇列;一種是最小優先佇列;每次取自佇列的第乙個元素分別是優先順序最大和優先順序最小的元素。

在stl中set和multiset都是基於紅黑樹實現的,查詢、刪除和插入操作都只需要o(logk)。

多路歸併排序

我們有如下乙個問題 對於若干個長度相同的序列,將其合併成乙個有序的序列。暴力的方法顯然是不可取的,這裡可以利用優先佇列來處理這個問題。首先從簡單的開始,對於2路歸併排序,設兩個序列為,將,排序,有 a1 a2 a3 an b1 b2 b3 bn 建立乙個優先佇列,佇列中首先存入元素 a1,0 b1,...

多路歸併排序

下面的問題描述及相關文字都參考於csdn中july的部落格,在此對july表示感謝。july的部落格位址如下 在對海量資料排序時,有時不能把資料全部匯入到記憶體中,這時需要用到多路歸併排序。比如輸入 乙個最多含有n個不重複的正整數 也就是說可能含有少於n個不重複正整數 的檔案,其中每個數都 小於等於...

多路歸併排序

雪壓枝頭低,雖低不著泥 今天準備放假,無聊看到乙個場景題,問題如下 有乙個檔案裡面儲存著很多很多很多的無序的數,然後要求進行乙個排序,記憶體限定,磁碟足夠 然後搗鼓了一下,學到了一種新技能 多路歸併排序 學習的過程是這樣的 第一步 把儲存著很多很多很多數的檔案進行切割,切割成n個小檔案,每個小檔案都...