动态数据集合中求top k大元素

第1大,第2大 ...第k大
k是这群体里最小的所以要建立个小顶堆
只需要维护一个大小为k的小顶堆 即可当来的元素(newCome)> 堆顶元素(smallTop),说明进来的元素有和堆顶竞争的资格,此时的堆顶被踢出 这时把进来的元素放到堆顶
newCome>smallTop,smallTop的左右孩子>smallTop,所以无法确认 newCome和smallTop的左右孩子的大小关系,
在newCome和smallTop的左右子节点找到最小的元素和newCome交换,然后继续比较newCome与被交换的左右孩子的大小关系
持续这个过程(堆化)即可

如果每次询问前K大数据,我们都基于当前的数据重新计算的话,那时间复杂度就是O(nlogK),n表示当前的数据的大小

部分代码
topn.php

$static_data=[2,5,3,1,0,7,6,10];//第3大
/*
2,5,3               2
2,5,3 1             2
2,5,3,1,0           2
2,5,3,1,0,7         3
2,5,3,1,0,7,6       5
2,5,3,1,0,7,6,10    6维持1个小顶堆 大小为3即可
*/
$heap=new Heap(3); //建立一个大小为3的小顶堆
foreach ($static_data as $v){echo $heap->topn($v).PHP_EOL;
}

heap.php

public function topn($data)
{//堆满了if ($this->isFull()) {if ($data > $this->dataArr[1]) {$this->dataArr[1] = $data;$this->smallHeapFirst();}} else {$this->dataArr[$this->count + 1] = $data;$this->count++;$this->smallHeapLast();}return $this->dataArr[1];}

完整代码

动态数据流求中位数

2,3,1,7,5       返回3
1,3,1,7,5,4     返回3,4
数据持续往里面进,每进来一个数,就询问中位数是谁们

step1 思路分析:


所谓中位数,就是中间大的1个或者2个元素,中位数满足的性质,中位数之前的数都它,之后的数都大于它
先以奇数个分析,偶数个原理一样
1.如果是固定的数据集合,比如数据为n个,中位数即为n/2+1 大的元素,此时只需维护一个大小为(n/2+1) 大小的小顶堆即可为什么不能是大顶堆呢,如果堆顶最大,除了知能找到这群集合的最大值外,其它的都无从知晓了如果是小顶堆,堆顶最小,数据集合比如为5个,第3大的元素肯定小于已经比较过的前2个数,即为中间元素但是现在是动态数据流,每次进来1个元素,都会询问中间元素和静态数据的区别是:不知道维护的小顶堆的大小了这时需要维护2个堆了,来了数据,分别放到这2个堆1个大顶堆,1个小顶堆,大顶堆的数据均小于小顶堆的数据,当要询问的时候如果是偶数个数据,两个堆的堆顶元素即为中间元素如果奇数个数据,两个堆中数据较多的那个堆的堆顶元素即为中间元素

step1 步骤分析

大顶堆为big,堆顶元素bigpeak,大小为bigsize,小顶堆称small,堆顶元素为smallpeak,大小为smallsize进来1个元素,big为空  :放入bigbig不为空:放入元素<bigpeak,放入到big放入元素>bigpeak, 放入到small放入1个元素完成后如果bigsize-smallsize>1,把big元素的堆顶元素拿掉 堆化big,把拿掉的元素放入small 然后堆化如果bigsize-smallsize<1,把small元素的堆顶元素拿掉 堆化small,把拿掉的元素放入big 然后堆化

findmiddle.php

$arr = [9, 8, 11, 4, 2, 6, 5, 1, -1, 3, 20, 10];
//$arr=[9,8,11,4,2,6,5,100];findMiddle($arr);//动态数据实时获取中位数
function findMiddle($arr)
{//大顶堆$bigHeap = new Heap(0, 1);//小顶堆$smallHeap = new Heap(0, 0);foreach ($arr as $k => $v) {if ($bigHeap->isEmpty()) {$bigHeap->insert($v);} else {$bigPeak = $bigHeap->peak();if ($v < $bigPeak) {$bigHeap->insert($v);} else {$smallHeap->insert($v);}if ($bigHeap->count - $smallHeap->count > 1) {$bigPeak = $bigHeap->deleteFirst();$smallHeap->insert($bigPeak);} elseif ($smallHeap->count - $bigHeap->count > 1) {$smallPeak = $smallHeap->deleteFirst();$bigHeap->insert($smallPeak);}}//实时获取中位数echo implode(',', midPeak($bigHeap, $smallHeap)) . PHP_EOL;}}function midPeak($heap1, $heap2)
{if ($heap1->count == $heap2->count) {$midArr = [$heap1->peak(), $heap2->peak()];} elseif ($heap2->count > $heap1->count) {$midArr = [$heap2->peak()];} else {$midArr = [$heap1->peak()];}return $midArr;
}

过程分析

几个重要的点
  • 两个堆元素数相等时中间元素为两个堆顶
    否者为较多元素堆的堆顶
  • 两者元素个数差值大于1时,要调整堆的元素个数
依次插入的元素 为 9, 8, 11, 4, 2, 6, 5, 1, -1, 3, 20, 10,大顶堆 称为big,小顶堆称为small,各自大小bigsize,smallsize,堆顶为bigpeak,smallpeak,9进来  big为空,插入big, bigsize-smallsize=1  不大于1       此时bigsize>smallsize  中间元素为bigpeak即为[9]
8进来  8<bigpeak,  插入big,bigsize-smallsize=2 大于1        此时bigpeak 需要从Big删除,big堆化,放入到small ,small堆化 ,此时bigsize=smallsize  所以中间元素为[bigpeak,smallpeak] 即为[8,9]
11进来 11>bigpeak(8),11插入small,此时smallsize=2,bigsize=1,差值不大于1,因为smallsize>bigsize,中间元素为[smallpeak] 即为[9]
4进来  4<bigpeak(8),4插入到big,big堆化,此时bigsize=2,smallsize=2,中间元素为[bigpeak,smallpeak] 即为[8,9]

此时堆图

2进来 2<8 ,2插入big然后堆化,bigsize=3,smallsize=2 所以此时中位数为[8]
6进来 6<8,6插入big后堆化 为下图

 此时,bigsize=4,smallsize=2,bigsize-smallsize>1,删除big的堆顶元素 堆化,然后把把删除的元素插入到small,堆化后此时big,small见下图,中间元素位[bigpeak,smallpeak]即 [6,8]

5进来 5<bigpeak(8),5插入big堆化
此时Bigsize=4,smallsize=3,差值不大于1,中间元素位bigpeak 即为[6]
之后的步骤同理

插入数据因为需要涉及堆化,所以时间复杂度变成了O(logn),但是求中位数我们只需要返回大顶堆的堆顶元素就可以了,所以时间复杂度就是O(1)

完整代码

转载于:https://www.cnblogs.com/HKUI/p/11483392.html

堆实战(动态数据流求top k大元素,动态数据流求中位数)相关推荐

  1. c语言实现分治法求第K大元素(详细解释)

    注:本文不对快速排序作任何解释,建议在对快速排序有一定了解后再阅览 一.问题分析 最简单的做法应该是直接选择先将集合排序(比如快速排序),然后直接以k为下标从有序集合中获取.但是这样做时间复杂度其实是 ...

  2. 动画: 快速排序 | 如何求第 K 大元素?

    写在前边 我们有这么一个需求,老板和我们说,要求我们做这么一个员工系统,公司员工的相关信息和为公司的贡献值都会在这个系统进行记录,每到月底评功轮赏的时候,根据员工这一个月的表现进行奖罚.你可能会说,这 ...

  3. leetcode 703. 数据流中的第K大元素 最小堆解法 c语言

    如题: 设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含 ...

  4. 从C语言的角度重构数据结构系列(七)-数据结构堆知识求解数据流中的第K大元素

    前言 在这里给自己打个广告,需要的小伙伴请自行订阅. python快速学习实战应用系列课程 https://blog.csdn.net/wenyusuran/category_2239261.html ...

  5. leetcode 703. 数据流中的第 K 大元素(堆)

    设计一个找到数据流中第 k 大元素的类(class).注意是排序后的第 k 大元素,不是第 k 个不同的元素. 请实现 KthLargest 类: KthLargest(int k, int[] nu ...

  6. 求数据流中的第K大元素

    题目 设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数 ...

  7. ⭐算法入门⭐《堆》中等02 —— LeetCode 703. 数据流中的第 K 大元素

    文章目录 一.题目 1.题目描述 2.基础框架 3.原题链接 二.解题报告 1.思路分析 2.时间复杂度 3.代码详解 三.本题小知识 四.加群须知 一.题目 1.题目描述   设计一个找到数据流中第 ...

  8. leetcode703. 数据流中的第K大元素(PriorityQueue 最小堆)

    设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中 ...

  9. LeetCode 703. 数据流中的第K大元素(优先队列)

    1. 题目 设计一个找到数据流中第K大元素的类(class). 注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器, ...

最新文章

  1. js 获取字符串中的中文
  2. 【异常】Error: ERROR 1012 (42M03): Table undefined. (state=42M03,code=1012)
  3. 中国工业节能减排产业项目盈利模式及投资风险预警报告2021-2027年
  4. 带电检测必要性_接地电阻检测分析的必要性
  5. 【Unity与23种设计模式】访问者模式(Visitor)
  6. 主链增幅最高飚至 152%,主流币却惊现回落;以太坊发币速度持续放缓
  7. [洛谷P3807]【模板】卢卡斯定理
  8. 「leetcode」463. 岛屿的周长【模拟便可】详解
  9. 我所见过的最简短、最灵活的javascript日期转字符串工具函数
  10. 下拉树取值与赋值单元格填报(取值赋值)
  11. 使用安卓的http进行数据的发送需要做的首先就是授权
  12. 软件界面设计思想方法
  13. led灯条串联图_一种串联控制LED灯条的制作方法
  14. MPEG-2压缩编码的视频基本流
  15. 6种抗辐射的经典美食
  16. Unity3d 实现节奏空间(Beat Saber)模型切割功能项目工程源码。
  17. 【Excel学习笔记13】对一个单元格内容进行条件分列,分列成多列
  18. python自己的手稿四之互动沟通
  19. Java从输入中读取一个数组
  20. mysql 当天日期零点_MySQL查询当天0点,昨天 mysql 获取当天0点 和 当天23点59分59秒...

热门文章

  1. 893B. Beautiful Divisors#美丽的因子(打表法)
  2. hdu 5212 : Code【莫比乌斯】
  3. 服务 托管型呼叫中心的核心竞争力
  4. 18岁的他从月薪2000到月薪11000经历了什么?
  5. Windows搭建golang开发平台
  6. 转载 想要在项目中引入其他项目的方法为
  7. JAVA escape/unescape
  8. 开发程序实现nginx代理节点状态检查及WEB界面展示
  9. Android: how to resolve Application’s parameter NullPointerException
  10. Windows Service 2008 R2 远程桌面关闭,自动注销的解决方法