剑指Offer41,数据流中的中位数 C++

1、题目描述

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
例如
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例 1
输入:
[“MedianFinder”,“addNum”,“addNum”,“findMedian”,“addNum”,“findMedian”]
[[],[1],[2],[],[3],[]]
输出:[null,null,null,1.50000,null,2.00000]
示例 2
输入:
[“MedianFinder”,“addNum”,“findMedian”,“addNum”,“findMedian”]
[[],[2],[],[3],[]]
输出:[null,null,2.00000,null,2.50000]

2、VS2019上运行

使用方法一:优先队列

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

class MedianFinder {
public:
    priority_queue<int, vector<int>, less<int>> queMin; // 存储较小一半数字的最大堆
    priority_queue<int, vector<int>, greater<int>> queMax; // 存储较大一半数字的最小堆

    MedianFinder() {}

    void addNum(int num) {
        if (queMin.empty() || num <= queMin.top()) { // 如果queMin为空或num小于等于queMin的堆顶元素
            queMin.push(num); // 将num添加到queMin
            if (queMax.size() + 1 < queMin.size()) { // 如果queMax的大小加1比queMin大,即queMin中的元素太多
                queMax.push(queMin.top()); // 将queMin的堆顶元素添加到queMax
                queMin.pop(); // 弹出queMin的堆顶元素
            }
        }
        else {
            queMax.push(num); // 将num添加到queMax
            if (queMax.size() > queMin.size()) { // 如果queMax的大小比queMin大,即queMax中的元素太多
                queMin.push(queMax.top()); // 将queMax的堆顶元素添加到queMin
                queMax.pop(); // 弹出queMax的堆顶元素
            }
        }
    }

    double findMedian() {
        if (queMin.size() > queMax.size()) { // 如果queMin的大小比queMax大,即元素总数为奇数
            return queMin.top(); // queMin的堆顶元素即为中位数
        }
        return (queMin.top() + queMax.top()) / 2.0; // 元素总数为偶数,返回queMin和queMax堆顶元素的平均值作为中位数
    }
};

int main() {
    MedianFinder* obj = new MedianFinder();
    cout << "null" << endl;
    obj->addNum(1);
    cout << "null" << endl;
    obj->addNum(2);
    cout << "null" << endl;
    double median1 = obj->findMedian();
    cout << median1 << endl;
    obj->addNum(3);
    cout << "null" << endl;
    double median2 = obj->findMedian();
    cout << median2 << endl;
    return 0;
}

运行结果:
null
null
null
1.5
null
2

3、解题思路

  • 1.类成员:
    queMin 是一个最大堆,用于存储较小的一半数字。堆顶元素是堆中的最大值。
    queMax 是一个最小堆,用于存储较大的一半数字。堆顶元素是堆中的最小值。
  • 2.构造函数 MedianFinder():
    初始化 queMin 和 queMax。
  • 3.addNum(int num) 函数:
    如果 queMin 为空或者 num 小于等于 queMin 的堆顶元素,将 num 插入到 queMin 中。
    如果 queMax 中的元素数量比 queMin 多,则取出 queMin 的堆顶元素,放入 queMax 中。
    否则,将 num 插入到 queMax 中。
    如果 queMax 中的元素数量比 queMin 多,则取出 queMax 的堆顶元素,放入 queMin 中。
  • 4.findMedian() 函数:
    如果 queMin 的大小大于 queMax 的大小,则中位数在 queMin 中,直接返回 queMin 的堆顶元素。
    否则,中位数应该是 queMin 的堆顶元素和 queMax 的堆顶元素的平均值,返回两者的平均值。

4、priority_queue

  • priority_queue 是一个在逻辑上模拟队列的容器适配器,它使用堆作为底层数据结构来实现其功能。
  • 堆(heap)是一种完全二叉树结构,具有以下性质:
    1.在一个最大堆中,父节点的键值大于或等于其子节点的键值。
    2.在一个最小堆中,父节点的键值小于或等于其子节点的键值。
  • priority_queue 使用堆结构来维护元素的优先级顺序:
    1.默认情况下,priority_queue 是一个最大堆,其中优先级最高的元素位于队列的顶部。
    2.如果通过自定义比较函数,可以将 priority_queue 转换为最小堆,其中优先级最低的元素位于顶部。
  • 对于 priority_queue,可以使用 push() 将元素插入队列,pop() 删除队列中的顶部元素,top() 返回顶部元素的引用,以及其他常见的操作函数。这些操作会根据堆的性质自动维护优先级顺序。
  • 虽然 priority_queue 在逻辑上表现为一个队列,但它实际上使用堆作为底层数据结构来管理元素的优先级。这使得在插入和删除元素时具有较高的效率,并保证队列中的元素是按照优先级排列的。
  • 完全二叉树(Complete Binary Tree)是一种特殊的二叉树,其中所有层级(除了最后一层或者倒数第二层)都被完全填满,且所有节点都尽可能地靠左排列
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值