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

应用一:优先级队列

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

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

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

优先级队列的应用场景

合并小文件

假设我们有一百个小文件,每个文件的大小是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%
相关推荐
wclass-zhengge2 分钟前
数据结构与算法篇(树 - 常见术语)
数据结构·算法
夜雨翦春韭9 分钟前
【代码随想录Day31】贪心算法Part05
java·数据结构·算法·leetcode·贪心算法
C++忠实粉丝6 小时前
前缀和(8)_矩阵区域和
数据结构·c++·线性代数·算法·矩阵
ZZZ_O^O6 小时前
二分查找算法——寻找旋转排序数组中的最小值&点名
数据结构·c++·学习·算法·二叉树
2401_857622667 小时前
SpringBoot框架下校园资料库的构建与优化
spring boot·后端·php
代码雕刻家7 小时前
数据结构-3.9.栈在递归中的应用
c语言·数据结构·算法
2402_857589367 小时前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
哎呦没8 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
Kalika0-09 小时前
猴子吃桃-C语言
c语言·开发语言·数据结构·算法
_.Switch9 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j