堆实战(动态数据流求top k大元素,动态数据流求中位数)
动态数据集合中求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大元素,动态数据流求中位数)相关推荐
- c语言实现分治法求第K大元素(详细解释)
注:本文不对快速排序作任何解释,建议在对快速排序有一定了解后再阅览 一.问题分析 最简单的做法应该是直接选择先将集合排序(比如快速排序),然后直接以k为下标从有序集合中获取.但是这样做时间复杂度其实是 ...
- 动画: 快速排序 | 如何求第 K 大元素?
写在前边 我们有这么一个需求,老板和我们说,要求我们做这么一个员工系统,公司员工的相关信息和为公司的贡献值都会在这个系统进行记录,每到月底评功轮赏的时候,根据员工这一个月的表现进行奖罚.你可能会说,这 ...
- leetcode 703. 数据流中的第K大元素 最小堆解法 c语言
如题: 设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含 ...
- 从C语言的角度重构数据结构系列(七)-数据结构堆知识求解数据流中的第K大元素
前言 在这里给自己打个广告,需要的小伙伴请自行订阅. python快速学习实战应用系列课程 https://blog.csdn.net/wenyusuran/category_2239261.html ...
- leetcode 703. 数据流中的第 K 大元素(堆)
设计一个找到数据流中第 k 大元素的类(class).注意是排序后的第 k 大元素,不是第 k 个不同的元素. 请实现 KthLargest 类: KthLargest(int k, int[] nu ...
- 求数据流中的第K大元素
题目 设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数 ...
- ⭐算法入门⭐《堆》中等02 —— LeetCode 703. 数据流中的第 K 大元素
文章目录 一.题目 1.题目描述 2.基础框架 3.原题链接 二.解题报告 1.思路分析 2.时间复杂度 3.代码详解 三.本题小知识 四.加群须知 一.题目 1.题目描述 设计一个找到数据流中第 ...
- leetcode703. 数据流中的第K大元素(PriorityQueue 最小堆)
设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中 ...
- LeetCode 703. 数据流中的第K大元素(优先队列)
1. 题目 设计一个找到数据流中第K大元素的类(class). 注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器, ...
最新文章
- js 获取字符串中的中文
- 【异常】Error: ERROR 1012 (42M03): Table undefined. (state=42M03,code=1012)
- 中国工业节能减排产业项目盈利模式及投资风险预警报告2021-2027年
- 带电检测必要性_接地电阻检测分析的必要性
- 【Unity与23种设计模式】访问者模式(Visitor)
- 主链增幅最高飚至 152%,主流币却惊现回落;以太坊发币速度持续放缓
- [洛谷P3807]【模板】卢卡斯定理
- 「leetcode」463. 岛屿的周长【模拟便可】详解
- 我所见过的最简短、最灵活的javascript日期转字符串工具函数
- 下拉树取值与赋值单元格填报(取值赋值)
- 使用安卓的http进行数据的发送需要做的首先就是授权
- 软件界面设计思想方法
- led灯条串联图_一种串联控制LED灯条的制作方法
- MPEG-2压缩编码的视频基本流
- 6种抗辐射的经典美食
- Unity3d 实现节奏空间(Beat Saber)模型切割功能项目工程源码。
- 【Excel学习笔记13】对一个单元格内容进行条件分列,分列成多列
- python自己的手稿四之互动沟通
- Java从输入中读取一个数组
- mysql 当天日期零点_MySQL查询当天0点,昨天 mysql 获取当天0点 和 当天23点59分59秒...
热门文章
- 893B. Beautiful Divisors#美丽的因子(打表法)
- hdu 5212 : Code【莫比乌斯】
- 服务 托管型呼叫中心的核心竞争力
- 18岁的他从月薪2000到月薪11000经历了什么?
- Windows搭建golang开发平台
- 转载 想要在项目中引入其他项目的方法为
- JAVA escape/unescape
- 开发程序实现nginx代理节点状态检查及WEB界面展示
- Android: how to resolve Application’s parameter NullPointerException
- Windows Service 2008 R2 远程桌面关闭,自动注销的解决方法