上圖是算法導論第三版第九章9.3所給出的步驟,根據這個步驟可以得到下面的代碼
/* 找中位數,只有五個數,直接排序取中間那個即可 */
int findMedian(vector<int> & nums, const int & left, const int & right) {
sort(nums.begin() + left, nums.begin() + right);
return nums[(left + right) >> 1];
}
/* 線性時間選擇第 k 小的數字 */
int linerTimeSelect(vector<int> & nums, const int & left, const int & right, const int & k) {
if (right – left < 75) {
sort(nums.begin() + left, nums.begin() + right);
return nums[left + k];
}
/* 五個數字一組 */
int nGroupCount = (right - left) / 5;
/* 中位數集合 */
vector<int> medians(nGroupCount);
for (int i = 0; i < nGroupCount; ++i) {
medians[i] = findMedian(nums, left + i * 5, left + (i + 1) * 5);
}
int nMedian = linerTimeSelect(medians, 0, nGroupCount, nGroupCount >> 1);
vector<int> S1;
vector<int> S2;
int nSameCount = 0; // 用來記錄相等元素的個數
for (int i = left; i < right; ++i) {
if (nums[i] < nMedian) {
S1.push_back(nums[i]);
}
else if (nums[i] > nMedian) {
S2.push_back(nums[i]);
}
else {
nSameCount++;
}
}
/* 在低位找 */
if (k < S1.size()) {
return linerTimeSelect(S1, 0, S1.size(), k);
}
/* 在中間找 */
else if (k < S1.size() + nSameCount) {
return nMedian;
}
/* 在高位找 */
else {
return linerTimeSelect(S2, 0, S2.size(), k - S1.size() - nSameCount);
}
return -1;
}
k是數組下標,比如要求第5小的數組,k應該讓它等於4
S1是小於median的數構成的數組
S2是大於median的數構成的數組
這段代碼和原書所給出的步驟有一點差異,主要是對於partition函數,我採用了數組實現,即小於median的數放在S1,大於median的數放在S2,然後通過S1和S2來繼續劃分而不是通過原數組加上兩個指針進行劃分,這樣便於代碼的實現但是降低了一點效率,還有一個小差異就是分組的時候,有一組可能不滿5個,我們不用管這一組元素,最後劃分的時候自然會被劃分進去。