一文通关数据结构的应用:堆的应用

应用一:优先级队列

  • 优先级队列:顾名思义,根据优先级来进行出队的队列

实现优先级队列的方式有很多种,用堆来来实现是最高效和直接的方式

  • 原因:一个堆就可以看成一个优先级队列,只是概念上的区分
    • 从优先级队列里面插入一个元素,相当于往堆中插入一个元素
    • 从优先级队列中取出优先级最高的元素,就相当于取出堆顶元素

优先级队列的应用场景

合并小文件

假设我们有一百个小文件,每个文件的大小是100MB,每个文件存储的都是有序的字符串,将这些小文件合并成一个大文件

  • 解决方式:
    • 1.从这100个文件里面选择每个文件选择一个,放入数组当中,然后比较,把最小的放入到大文件中,并从数据中删除
    • 2.从找到最小的字符串对应的文件再取下一个,重新执行步骤1,直到所有的数据都放入大文件当中

问题:每次取出都需要遍历数组

  • 优化方式:
    • 使用小顶堆
    • 1.每次从小文件当中取出的数据放入小顶堆当中,堆顶的元素,也就是优先级队列队首的元素就是最小的字符串
    • 2.重复步骤1

删除堆顶数据和往堆中插入数据的时间复杂度都是O(logn),n表示堆中的数据个数

高性能定时器

假设有一个定时器,定时器中维护了很多任务,每个任务都设定了一个要触发的时间点

  • 定时器工作:每过一个很小的单位时间(e.g.一秒),就扫描一遍任务

  • 缺点:

    • 1.任务的执行时间离当前时间可能还有很久,也就意味着前面时间的扫描都是徒劳无功
    • 2.每次都要扫描整个任务列表,如果任务列表很大,势必比较耗时
  • 优化思路:

    • 可以用优先队列来解决,按照任务设定的时间将这些任务存储在优先级队列当中,堆顶就是最先执行的任务
  • 这样就不需要每隔一秒去扫描,拿到首任务的执行时间与当前时间得到一个时间间隔,这样可以在时间间隔到来的时候再去执行,后面的任务也是这个逻辑

应用二:利用堆求TopK

  • 求TopK的问题分成两类:
    • 一类是针对静态数据的集合:数据集合事先确定,不会再变
    • 一类是针对动态数据集合:数据集合事先不确定,有数据动态加入到集合

针对静态数据

在一个包含n个数据的数组中,查找前K个大的数据

可以维护一个大小为K的小顶堆,顺序遍历数组,从数组中取出数据与堆顶比较,如果比堆顶元素大,就把堆顶元素删除,并且将这个元素插入到堆中,如果比堆顶小就不做处理

遍历数组需要O(N),一次堆化操作需要O(logk),最坏情况,n个元素都需要堆化,时间复杂度为O(nlogk)

针对动态数据

针对动态数据求得TopK,就是实时TopK

e.g.一个数据集合中 有两个操作,一个是添加数据,另一个询问当前的前 K 大数据。

  • 如果每次询问前 K 大数据,我们都基于当前的数据重新计算的话,那时间复杂度就是 O(nlogK),n 表示当前的数据的大小
  • 可以一直都维护一个 K 大小的小顶 堆,当有数据被添加到集合中时,我们就拿它与堆顶的元素对比

应用三:利用堆求中位数

中位数,顾名思义,就是处在中间位置的那个数

  • 如果总数是奇数的话,第 n/2+1个数据就是中位数
  • 如果总数是偶数的话,第 n/2,n/2+1个数据就是中位数

假设取n/2

对于一组静态数据,中位数是固定的,可以先排序,第n/2个数据就是中位数。每次询问中位数的时候,直接返回这个固定的值就好了

  • 但是如果是动态数据集合的话,中位数在不停的变化,如果再用排序的方法,每次询问中位数的时候,都排序就效率比较低

使用堆来解决

维护两个堆:一个大顶堆(存储前半部分数据),一个小顶堆(存储后半部分数据),且小顶堆中的数据都大于大顶堆中的数据

  • e.g.有n个数据,从小到大排序,前n/2存储在大顶堆,后n/2存储在小顶堆,这样大顶堆的堆顶就是我们要寻找的数
  • 如果n是奇数,大顶堆就存储n/2+1个数据,小顶堆就存储n/2个数据

如果数据是动态的情况下

如何进行堆的调整?

  • 如果新加入的数据小于等于大顶堆的堆顶元素,我们就将这个新数据插入到大顶堆
  • 如果新加入的数据大于等于小顶堆的堆顶元素,我们就将这个新数据插入到小顶堆

这样可能出现n从奇数到偶数,偶数到奇数的变换问题,可以从一个堆中不停将堆顶元素移到另外一个堆中

  • 可以利用两个堆,一个大顶堆、一个小顶堆,实现在动态数据集合中求中位数的操作
  • 插入数据因为需要涉及堆化,所以时间复杂度变成了 O(logn),但是求中位数我们只需要返回大顶堆的堆顶元素就可以了,所以时间复杂度就是 O(1)

中位数可以类推到99%,80%

  • 将大顶堆和小顶堆里面的数据进行调整,比如大顶堆是占99%,小顶堆占1%
相关推荐
拖孩23 分钟前
流量主门槛从 500 降到 100,我的小程序上线 18 小时够到了线
前端·后端·微信小程序
养军博客31 分钟前
Spring Security 4.x / 5.x / 6.x 配置全对比:前后端不分离与前后端分离
java·后端·spring·springsecurity
wifi___32 分钟前
SpringBoot自动装配原理
java·spring boot·后端
日日大王学编程35 分钟前
AI 时代后端方向新人的未来规划与看法
人工智能·后端·python·ai·golang
Fox爱分享1 小时前
都问程序员双十一买什么,我的答案一定是这块专业编程显示器
后端·程序员·ai编程
CCblandy1 小时前
缓存淘汰实测:一次全表扫描把 LRU 命中率从 46% 打到 38%,W-TinyLFU 守住 50% 却贵 11 倍
后端·python·缓存·性能优化·架构
武子康1 小时前
DOA 100%、GSC 改善 12 dB,ESP32-P4 远场拾音就能用了吗?
人工智能·后端·agent
愚农搬码2 小时前
企业为什么需要表单引擎,而不是继续手写 Vue 表单?
后端
孟陬2 小时前
技术周刊#158:ChatGPT 智能 UI 底层原理、个人智能体协议正式发布、一条 POST 请求即可锁死 Next.js 服务
人工智能·后端·全栈
小蒜学长2 小时前
基于SpringBoot+Vue的云南地区扶贫助农系统的设计与实现(代码+数据库+LW)
java·vue.js·spring boot·后端·乡村振兴