c++实现最坏时间为线性时间的快速选择算法

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章