這節給的題目是從一串數字中尋找最大的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找...