程式設計之美 2 5 尋找最大的K個數

2022-09-23 20:09:08 字數 2839 閱讀 5024

這節給的題目是從一串數字中尋找最大的k個數,而且考慮資料量比較大的情況。

解法一首先考慮了快速排序和堆排序,但是,它們對所有的資料都進行了排序,然後考慮使用部分排序演算法,如選擇排序和交換排序,它們能夠從一串數字中選擇前k個,但是,效率依舊不高。

解法二使用了快速排序演算法,在快速排序演算法中,用乙個樞軸將數列分成了兩個部分,左邊的比樞軸小,右邊的比樞軸大,然後再分別對兩個數列進行遞迴,在這裡,用樞軸來分的時候,左邊的比樞軸大,右邊的比樞軸小,當樞軸左邊的元素個數大於或者等於k,那麼,就返回左邊數列的最大的k個數,當樞軸左邊的元素個數n小於k,就返回左邊數列和右邊數列的最大的n-k-1個數。書中在實現的時候用到了兩個陣列,這裡,我就按照快速排序的過程實現一遍。

#include

#include

#include

#include

#include

using namespace std;

vector::iterator find_k(vector::iterator beg, vector::iterator end, int k)

vector::iterator left = beg, right = end - 1;

srand(time(null));

int index = rand() % n;

iter_swap(beg, beg + index);

while(left < right)

while(*left > *right && left < right)

++left;

if(left < right)

} n = left - beg;

if(n + 1 >= k)

return find_k(beg, left + 1, k);

else

return find_k(left + 1, end, k - n - 1);

}int main()

; vector ivec(arr, arr + 8);

int k = 5;

vector::iterator iter = find_k(ivec.begin(), ivec.end(), k);

copy(ivec.begin(), iter, ostream_iterator(cout, " "));

return 0;

}上述的**跟快速排序很像吧?為了使樞軸隨機,不一定是第乙個元素,**使用了隨機數生成函式,將第乙個元素與後面的某乙個元素進行調換。**執行結果:

解法三是採用跟解法二類似的二分法,從二進位制的角度看,將整數從高位到低位某位為0或者1進行二分。

解法四中,首先提出了乙個問題,上面的方法都需要對資料訪問多次,如果資料量很大的情況下,資料無法全都裝入到記憶體中,會對效率造成很大的影響。

於是,就要求盡可能少地遍歷所有資料。

首先,假設資料的前k個資料就是最大的k個資料,如果第k+1個資料比前k個資料的最小值小,那麼前k+1個元素的最大的k個元素就是前k個元素,如果第k+1個資料比前k個資料的最小值大,那麼,前k+1個元素的最大的k個元素就是將前k個元素中最小的元素剔除掉就是了。這樣重複操作,遍歷完所有的元素後,最大的k個資料也就出來了,而且只遍歷了一遍資料。按照上述方案,可以得到以下**:

#include

#include

#include

using namespace std;

vector::iterator min_iter(vector::iterator beg, vector::iterator end)

++beg;

} return m;

}void find_k(vector::iterator beg, vector::iterator end, int k)

vector::iterator iter = beg + k;

while(iter != end)

++iter; }}

int main()

; vector ivec(arr, arr + 8);

int k = 5;

find_k(ivec.begin(), ivec.end(), k);

if(ivec.size() < k)

else

return 0;

}思路上面已經解釋了,**就不做過多解釋。

以上**只需要遍歷一次所有的元素,主要的瓶頸就在於min_iter()求前k個元素的最小值上,那麼,能夠快速地得到前k個元素的最小值嗎?

可以,使用堆,對前k個元素建小頂堆,那麼就能夠快速得到前k個元素的最小值了。這裡只給出核心函式:

void find_k(vector::iterator beg, vector::iterator end, int k)

make_heap(beg, beg + n, greater());

vector::iterator iter = beg + n;

while(iter != end)

++iter;

}}解法五首先提出了一種使用計數的方式,對每個值出現的次數進行計數,然後再從高到低得到最大的k個數,但是,這種方法僅適用於元素時正整數且取值範圍不大的資料。

擴充套件問題:

1 如果需要找出n個數中最大的k個不同的浮點數呢?注意這裡的「不同」兩個字。

當然,最簡單的辦法就是對n個數進行排序,最後相等的數字相鄰存放,然後從高到低遍歷,遇到相等的不進行計數,最後就得到了最大的k個數。

如果可以對數列進行修改,可以先進行預處理,把相同的資料剔除掉,然後求得最大的k個數,不過,預處理的代價也很高。

2 如果是找到第k到m(0

最簡單的辦法就是利用本節的方法,找到最大的k-1個數和最小的m-1個數,剩下的就是第k到m大的數。

《程式設計之美》2 5尋找最大的K個數

問題 有很多個無序的數 假設為n個 怎麼選出其中最大的k個數?kay s word kay的理解 很多 好多好多,無法儲存,因此首先排除了對輸入數排序的解法,而採用小容量陣列整理大的輸入資料,即 開大小為k的陣列,通過遍歷n個輸入陣列,每遍歷乙個數num,檢查k陣列的最小數,如果比num小,則用nu...

程式設計之美2 5 尋找最大的K個數

問題 從一組數中選出其中最大的k個數,當這組數的個數為幾百 幾百萬 幾百億時分別適合採用哪些演算法?個數為幾百時,使用順序統計法 看演算法導論第9章 演算法思想是對輸入陣列進行遞迴劃分,一邊的資料小於選定數,另一邊的資料大於等於選定數。但和快速排序不同的是,快速排序會遞迴處理劃分的兩邊,而順序統計法...

程式設計之美 2 5 尋找最大的K個數

今天看演算法分析是,看到乙個這樣的問題,就是在一堆資料中查詢到第k個大的值。名稱是 設計一組n個數,確定其中第k個最大值,這是乙個選擇問題,當然,解決這個問題的方法很多,本人在網上搜尋了一番,查詢到以下的方式,決定很好,推薦給大家。所謂 第 前 k大數問題 指的是在長度為n n k 的亂序陣列中s找...