赞
踩
快速选择算法(最优解)
- #include <iostream>
- #include <vector>
- #include <algorithm>
-
- using namespace std;
-
- class Solution {
- private:
- // 快速选择算法中的分区函数
- int partition(vector<int>& nums, int left, int right) {
- int pivot = nums[right]; // 选择最右边的元素作为枢纽元
- int i = left - 1; // i 指向小于等于 pivot 的元素
- for (int j = left; j < right; j++) {
- if (nums[j] <= pivot) {
- i++;
- swap(nums[i], nums[j]); // 将小于等于 pivot 的元素交换到左侧
- }
- }
- swap(nums[i + 1], nums[right]); // 将 pivot 放到正确的位置
- return i + 1; // 返回 pivot 的索引
- }
-
- // 快速选择算法
- int quickSelect(vector<int>& nums, int left, int right, int k) {
- if (left == right) return nums[left]; // 只有一个元素,直接返回
-
- int pivotIndex = partition(nums, left, right); // 获取 pivot 的索引
- if (k == pivotIndex) {
- return nums[k]; // 找到第 k 个最大元素
- } else if (k < pivotIndex) {
- return quickSelect(nums, left, pivotIndex - 1, k); // 在左侧继续查找
- } else {
- return quickSelect(nums, pivotIndex + 1, right, k); // 在右侧继续查找
- }
- }
-
- public:
- double findMedian(vector<int>& nums) {
- int n = nums.size();
- if (n % 2 == 1) {
- return quickSelect(nums, 0, n - 1, n / 2); // 奇数个元素,直接找到中位数
- } else {
- int left = quickSelect(nums, 0, n - 1, n / 2 - 1); // 找到第 n/2-1 个最大元素
- int right = quickSelect(nums, 0, n - 1, n / 2); // 找到第 n/2 个最大元素
- return (left + right) / 2.0; // 计算中位数
- }
- }
- };
-
- int main() {
- vector<int> nums = {3, 2, 1, 5, 6, 4};
- Solution sol;
- double median = sol.findMedian(nums);
- cout << "中位数是:" << median << endl;
- return 0;
- }

如果数组太大,无法一次性加载到内存中,或者我们不能修改原数组,可以考虑使用基于分块的近似算法:
基于分块的近似算法(适用于超大数据集)
- class Solution {
- public:
- double findApproximateMedian(const vector<int>& nums) {
- const int BUCKET_SIZE = 1000; // 可以根据实际情况调整
- vector<int> count(BUCKET_SIZE, 0);
- int minVal = INT_MAX, maxVal = INT_MIN;
-
- // 第一次遍历:找到最小值和最大值
- for (int num : nums) {
- minVal = min(minVal, num);
- maxVal = max(maxVal, num);
- }
-
- double bucketSize = (maxVal - minVal + 1.0) / BUCKET_SIZE;
-
- // 第二次遍历:统计每个桶的元素数量
- for (int num : nums) {
- int index = min((int)((num - minVal) / bucketSize), BUCKET_SIZE - 1);
- count[index]++;
- }
-
- // 找到中位数所在的桶
- int medianCount = (nums.size() + 1) / 2;
- int bucketIndex = 0;
- int sum = 0;
- while (sum < medianCount) {
- sum += count[bucketIndex];
- bucketIndex++;
- }
- bucketIndex--;
-
- // 计算近似中位数
- double medianLow = minVal + bucketIndex * bucketSize;
- double medianHigh = minVal + (bucketIndex + 1) * bucketSize;
- return (medianLow + medianHigh) / 2.0;
- }
- };

这个算法的优点:
缺点是结果是近似值,不是精确的中位数。精确度可以通过增加桶的数量来提高,但会增加空间复杂度。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。