📌  相关文章
📜  使用C++ STL在线性时间内查找未排序数组的中位数(1)

📅  最后修改于: 2023-12-03 15:36:35.388000             🧑  作者: Mango

使用C++ STL在线性时间内查找未排序数组的中位数

如果您需要对一个未排序的数组进行中位数查找,最常见的方法是对该数组进行排序,然后找到中间元素。但排序算法的时间复杂度通常为 O(nlogn),这显然不符合要求。

C++ 标准模板库(STL)中的 nth_element 算法提供了一种在线性时间内查找未排序数组的中位数的方法。其时间复杂度为 O(n)。nth_element 做的事情不是完全排序,而是将数组中第 n 大的元素放在第 n 个位置上,左边的元素都小于第 n 大的元素,右边的元素都大于第 n 大的元素。因此,我们可以用 nth_element 查找中位数,也可以查找其他分位数。

下面是使用 STL 的 nth_element 实现查找未排序数组的中位数的示例代码:

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int main() {
    vector<int> nums = {3, 7, 2, 8, 1, 5, 6, 4};

    // 使用 nth_element 查找中位数
    nth_element(nums.begin(), nums.begin() + nums.size() / 2, nums.end());

    // 如果数组长度为奇数,则中位数就是第 n / 2 大的数
    if (nums.size() % 2 != 0) {
        cout << "中位数为:" << nums[nums.size() / 2] << endl;
    } else {
        // 如果数组长度为偶数,则中位数是第 n / 2 大和第 n / 2 - 1 大的数的平均数
        nth_element(nums.begin(), nums.begin() + nums.size() / 2 - 1, nums.end());
        double median = (double)(nums[nums.size() / 2 - 1] + nums[nums.size() / 2]) / 2;
        cout << "中位数为:" << median << endl;
    }
    return 0;
}

输出结果为:

中位数为:4.5

代码解析:

首先我们定义了一个 vector 类型的数组 nums,其中存储了一些无序的整数。我们使用 nth_element 算法查找中位数,具体来说,我们调用了以下函数:

nth_element(nums.begin(), nums.begin() + nums.size() / 2, nums.end());

其中,nums.begin() 和 nums.end() 分别指向 nums 数组的起始位置和末尾位置。第二个参数是一个迭代器,指向了中位数的位置,即第 n / 2 大的数所在的位置。由于 nth_element 的排序规则并不与元素的值有关,因此无法预测中位数所在的位置,我们使用 nums.begin() + nums.size() / 2 来指定中位数的位置。这里,nums.size() / 2 表示数组的中间位置,我们在前面加上 nums.begin(),表示从数组的起始位置开始第 n / 2 个元素就是中位数。

如果 nums 数组长度是奇数,那么中位数就是 nums[nums.size() / 2]。如果 nums 数组长度是偶数,那么中位数是第 nums.size() / 2 大和第 nums.size() / 2 - 1 大的数的平均数。由于我们已经使用 nth_element 将数组中第 nums.size() / 2 大的数放到了正确的位置上,因此此时 nums[nums.size() / 2 - 1] 就是第 nums.size() / 2 - 1 大的数,我们只需要再次调用 nth_element 查找第 nums.size() / 2 - 1 大的数即可,然后将这两个元素相加再除以 2 就可得到中位数。