C語言用堆思想解決TopK問題

2021-08-19 16:27:14 字數 2200 閱讀 8679

之前介紹了堆的一些操作,對堆排序的操作是在提前建立了堆的資料結構的基礎上直接呼叫以前的資料結構,但是今天我們要做的是,假如現在你去面試或者遇到問題的時候沒有堆這個資料結構可以直接呼叫的時候怎麼辦呢?難道要現場建立乙個嗎?也不是說不可以,但是畢竟你的時間是有限的,而且其實可以通過直接對陣列的操作來進行堆的操作。

其實topk問題就是複雜之後的堆排序問題,所以今天我主要給大家介紹乙個

topk

問題,其實

topk

問題簡單來說就是在海量的資料中找到最大的

k個數值。就那我們正常的排序來看例如:氣泡排序,在解決海量資料的時候我們就要考慮你程式的複雜度。包括現在很多程式也是,你實現你的思想並不難,難的是你的演算法,你有乙個好的演算法就等於讓你的程式有了更高的智商來解決這個問題。就能又快有準解決你所想要解決的問題。繼續說我們之前所熟悉的氣泡排序,這裡大家學了時間複雜度之後都知道,氣泡排序是乙個時間複雜度為o(

n)的處理程式,當你有

1500

個資料的時候你就需要

2250000

次計算,並且當隨著你的資料的不斷增加,這個數量是急劇增長的。所以在我們處理更多的資料的時候就需要好的演算法。

這裡就是用到了我們的堆,首先還是之前的問題,topk是找到最大的

k個資料,既然是這樣,那是不是就意味著,和我們之前對堆的操作一樣,現在將你的海量資料進行建造大堆等堆建立好了之後,選出來最大的乙個,也就是堆頂的資料,然後讓最後乙個補上來,繼續開始一次向下調整。這樣實現起來是沒有任何問題的,但是在我們看起來他並沒有那麼的簡單,那麼的方便。這裡有沒有更好的辦法呢?我其實你想假如你現在的前

k個元素正好就是最大的元素,那當你建立好整個堆之後,你還是需要不斷的去掉頂,然後不斷的去向下調整。這裡有沒有有點更好的辦法呢?

其實說到這裡我想大家也有一定的思路了,那就是我要top的

k個元素也就是最大的

k個,那我能不能只建立乙個

k大小的堆,其實完全可以,那大家想一下我是要建立乙個大堆還是乙個小堆呢?

-------------

小堆!為什麼呢?舉個例子假如你現在要找最大的前十個數,然後你建立了乙個十個數字的大堆,現在堆頂是十個數裡邊最大的數,堆頂其實可以想象乙個棧頂,他才是你對資料操作的關鍵位置,假如你建立的是大堆,也就是前十個數最大的在堆頂,那假如第十乙個數比堆頂小,那你能證明什麼呢?他該不該入堆呢?萬一他比十個數字所有都小?那萬一他只比堆頂元素小呢?但是你又不能把這個數和堆裡所有元素都比較呢?所以你要建立乙個小堆,堆頂是最小的元素,如果你接下來比較的數堆頂大,那就說明這個數要替代了堆頂的數了,當他替換堆頂元素之後進行一次向下調整,這時候堆裡最小的元素又跑到堆頂了,只要比他大那就把它替換掉,當整個陣列遍歷完畢之後,堆裡的元素就是最大的十個元素了。

那我們應該如何在直接在陣列上進行堆的一系列操作呢?

void heaptopk(int *a, int n, int k)

for (i = k; i < num; i++)

}for (i = 0; i < k; i++)

}

這裡用到的向下調整函式我之前雖然有些過,但是,等下我還是會放在後邊,方便大家看。

這裡首先我在陣列上的前k個數建立乙個堆。

for (; i >= 0; i--)

其實這裡和我們直接在堆資料結構進行操作是一樣的,不過這裡操作的是陣列的前k個元素。

for (i = k; i < num; i++)

}

然後通過第k個開始往後每個元素和堆頂進行比較,如果打的話就進行交換,交換之後一定要記著再次進行向下調整函式。才能保證交換之後的陣列堆仍然是乙個小堆,堆頂元素仍然可以進行比較。

#define _crt_secure_no_warnings 1

#include#includevoid adjustdown(int *a, int n, int root)

else

break;

}}

這是向下調整函式。

int main()

;heaptopk(arr, 10, 5);

system("pause");

return 0;

}

這是主函式進行測試的時候使用的。

堆解決topK問題

小根堆取的話,複雜度過高o nlogn 資料量過大會超時 class solution 堆排序 小根堆 return ans void heap vector int arr start while start 1 else if arr 2 start 1 arr 2 start 2 else s...

用c語言解決日期問題

用c語言計算日期。方法一 先算出到已知日期前的所有天數然後對7求餘數。計算所有天數的函式如下 int year sum int a int b int c 計算到輸入日期前的總共天數 平年每個月的天數 int e 閏年每個月的天數 while a 1 else sum 365 j 366 i if ...

用進製思想解決組合問題

先對我們要解決的問題進行乙個描述 如上圖所示,原來有個字串 123 現在有個對應關係,可以把1換成 a a 甲 可以把2換成 b b 可以把3換成 c 那麼,有多少種組合字串的方式呢 注意順序不變 我們可以計算得到 4 3 2 24 種組合方式 包括原字串 123 在內 我們用 0 23這24 個數...