C++实现一个数据流中,随时可以取得中位数

1. 题目描述

Leetcode295: 数据流的中位数
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。

例如,

[2,3,4] 的中位数是 3

[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构:

void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。

示例:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3) 
findMedian() -> 2

2.思路分析

采用优先队列,也就是大根堆跟小根堆,我们将较小的n/2个数放到大根堆中,将较大的n/2个数放到小根堆中,显然,如果n是偶数,那么大根堆的堆顶跟小根堆的堆顶就是我们要找的两个中位数,将其相加除以2作为结果返回即可。如果n是奇数,那么就看大根堆跟小根堆谁的节点个数比另一个堆多一个,节点数量多的那个堆的堆顶就是我们要找的中位数,此时我们直接返回结果即可。

注意:

  1. 对于取堆顶元素的操作的时间复杂度是常数级别的。

  2. 插入新节点时我们需要判断节点的值是否小于大根堆堆顶的值或者大于小根堆堆顶的值,如果小于大根堆堆顶的值,那么节点应该插入大根堆,反过来应该插入小根堆。

  3. 每次插入新节点我们还需要判断两个堆之间的元素个数是否平衡。插入新节点后,我们判断两个堆的元素个数,如果相差为2那么我们就要对堆进行调整。比如新插入一个节点到小根堆中,而此时大根堆的个数+1小于小根堆的节点个数,这个时候只需要将小根堆的堆顶元素弹出,然后将这个弹出的元素插入大根堆即可。反过来也是一样的操作。为什么可以这样做呢?这是因为我们说了小根堆保存的是较大的n/2个数,而小根堆的堆顶是小根堆中最小的元素,同时也是大根堆中最大的元素,因此我们将这个堆顶元素弹出并插入大根堆的操作并不会破坏“小根堆保存较大的n/2个数,大根堆保存较小的n/2”这样的前提。

3. 代码

这里还是借助了std::priority_queue来实现大跟堆和小根堆。

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

class MedianFinder {
 private:
     std::priority_queue<int, std::vector<int>, std::less<int> > maxHeap;
     std::priority_queue<int, std::vector<int>, std::greater<int> > minHeap;
 public:
    /** initialize your data structure here. */
    MedianFinder() {

    }

    void addNum(int num) {
        if (maxHeap.empty()) {  // if maxHeap is empty, push it directly
            maxHeap.push(num);
            return;
        }
        if (maxHeap.top()>= num) {  // small number push to maxHeap
            maxHeap.push(num);
        } else {    // max number push to minHeap
            if (minHeap.empty()) {  // if minHeap is empty, push it directly
                minHeap.push(num);
                return;
            }
            if (minHeap.top() >= num) { // push it to maxHeap
                maxHeap.push(num);
            } else {    // push it to minHeap
                minHeap.push(num);
            }
        }
        // adjust maxHeap and minHeap, ensure the different size <= 1
        if (maxHeap.size() == minHeap.size() + 2) { // maxHeap - minHeap = 2, adjust
            int maxTmp = maxHeap.top();
            minHeap.push(maxTmp);
            maxHeap.pop();
        }
        if (minHeap.size() == maxHeap.size() + 2) { // minHeap - maxHeap = 2, adjust
            int minTmp = minHeap.top();
            maxHeap.push(minTmp);
            minHeap.pop();
        }

    }

    double findMedian() {
        int maxHeapSize = maxHeap.size();
        int minHeapSize = minHeap.size();
        if (maxHeapSize + minHeapSize == 0) {   // empty return 0.0
            return 0.0;
        }
        int maxHeapTop = maxHeap.top();
        int minHeapTop = minHeap.top();
        if (((maxHeapSize + minHeapSize) & 1) == 0) {
            return (maxHeapTop + minHeapTop) / 2.0;
        }
        else {    // total sum is odd
            return maxHeapSize > minHeapSize ? (double)maxHeapTop : (double)minHeapTop;
        }
    }
};

 int main () {
    MedianFinder* obj = new MedianFinder();
    obj->addNum(1);
    obj->addNum(2);
    std::cout << obj->findMedian() << std::endl;
    obj->addNum(3);
    std::cout << obj->findMedian() << std::endl;

    return 0;
 }

在这里插入图片描述

4. 参考文献

  1. LeetCode-295 数据流的中位数

贪心的题目暂时到这里,后面可能是动态规划的一些题目了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
谭浩强教授,我国著名计算机教育专家。1934年生。1958年清华大学毕业。学生时代曾担任清华大学学生会主席、北京市人民代表。他是我国计算机普及和高校计算机基础教育开拓者之一,现任全国高等院校计算机基础教育研究会会长、教育部全国计算机应用技术证书考试委员会主任委员。 谭浩强教授创造了3个世界纪录:(1)20年来他(及和他人合作)共编著出版了130本计算机著作,此外主编了250多本计算机书籍,是出版科技著作量最多的人。(2)他编著和主编的书发行量超过4500万册,是读者最多的科技作家。我国平均每30人、知识分子每1.5人就拥有1本谭浩强教授编著的书。(3)他和别人合作编著的《BASIC语言》发行了1200万册,创科技书籍发行量的世界纪录。此外,他编著的《C程序设计》发行了600万册。他曾在央电视台主讲了BASIC,FORTRAN,COBOL,Pascal,QBASIC,C,Visual Basic七种计算机语言,观众超过300万人。 在我国学习计算机的人很少有不知道谭浩强教授的。他善于用容易理解的方法和语言说明复杂的概念。许多人认为他开创了计算机书籍贴近大众的新风,为我国的计算机普及事业做出了重要的贡献。 谭浩强教授曾获全国高校教学成果国家级奖、国家科技进步奖,以及北京市政府授予的“有突出贡献专家”称号。《计算机世界》报组织的“世纪评选”把他评为我国“20世纪最有影响的IT人物”10个人之一(排在第2位)。他的功绩是把千百万群众带入计算机的大门。 1 C语言概述 1.1 C语言的发展过程 1.2 当代最优秀的程序设计语言 1.3 C语言版本 1.4 C语言的特点 1.5 面向对象的程序设计语言 1.6 C和C++ 1.7 简单的C程序介绍 1.8 输入和输出函 1.9 C源程序的结构特点 1.10 书写程序时应遵循的规则 1.11 C语言的字符集 1.12 C语言词汇 1.13 Turbo C 2.0 集成开发环境的使用 1.13.1 Turbo C 2.0 简介和启动 1.13.2 Turbo C 2.0 集成开发环境 1.13.3 File菜单 1.13.4 Edit 菜单 1.13.5 Run 菜单 1.13.6 Compile 菜单 11.13.7 Project 菜单 1.13.8 Options菜单 1.13.9 Debug 菜单 1.13.10 Break/watch 菜单 1.13.11 Turbo C 2.0 的配置文件 2 程序的灵魂—算法 2.1 算法的概念 21 2.2 简单算法举例 21 2.3 算法的特性 24 2.4 怎样表示一个算法 24 2.4.1 用自然语言表示算法 24 2.4.2 用流程图表示算法 24 2.4.3 三种基本结构和改进的流程图 28 2.4.4 用N-S 流程图表示算法 29 2.4.5 用伪代码表示算法 30 2.4.6 用计算机语言表示算法 31 2.5 结构化程序设计方法 31 3 据类型、运算符与表达式 3.1 C语言的据类型 32 3.2 常量与变量 33 23.2.1 常量和符号常量 33 3.2.2 变量 33 3.3 整型据 34 3.3.1 整型常量的表示方法 34 3.3.2 整型变量 35 3.4 实型据 37 3.4.1 实型常量的表示方法 37 3.4.2 实型变量 38 3.4.3 实型常的类型 39 3.5 字符型据 39 3.5.1 字符常量 39 3.5.2 转义字符 39 3.5.3 字符变量 40 3.5.4 字符据在内存的存储形式及使用方法 41 3.5.5 字符串常量 41 3.5.6 符号常量 42 3.6 变量赋初值 42 3.7 各类值型据之间的混合运算 43 3.8 算术运算符和算术表达式 44 3.8.1 C运算符简介 44 3.8.2 算术运算符和算术表达式 45 3.9 赋值运算符和赋值表达式 47 33.10 逗号运算符和逗号表达式 48 3.11 小结 49 3.11.1 C的据类型 49 3.11.2 基本类型的分类及特点 49 3.11.3 常量后缀 49 3.11.4 常量类型 49 3.11.5 据类型转换 49 3.11.6 运算符优先级和结合性 50 表达式 50 4 最简单的 C程序设计—顺序程序设计 4.1 C语句概述 51 4.2 赋值语句 53 4.3 据输入输出的概念及在 C 语言实现 54 4.4 字符据的输入输出 54 4.4.1 putchar 函(字符输出函) 54 4.4.2 getchar函(键盘输入函) 55 4.5 格式输入与输出 55 4.5.1 printf 函(格式输出函) 56 4.5.2 scanf函(格式输入函)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值