上图是算法导论第三版第九章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个,我们不用管这一组元素,最后划分的时候自然会被划分进去。