堆的应用

扫码关注公众号,获取更多内容

目录

一、优先级队列

1、合并有序小文件

2、高性能定时器

二、利用堆求Top K


一、优先级队列

1、合并有序小文件

场景:有100个小文件,每个文件大小都是100MB,每个文件中存储的都是有序的字符串。我们将这100个小文件合并成一个有序的大文件。

整体思路与归并排序中的合并函数类似,从这100个文件中,各取第一个字符串,放入数组中,然后比较大小,将最小的那个字符串放入合并后的大文件中,并从数组中删除。

假如这个最小的字符串来自于16.txt这个文件,我们就再从这个文件取下一个字符串,放到数组中,重新比较大小,并且选择最小的放到合并后的大文件,将它从数组中删除。以此类推,知道所有的文件中的数据都放入到大文件为止。

 这里我们用数组来存储从小文件中取出的字符串。每次从数组中取最小字符串都需要遍历整个数组,这不是很高效。有什么更高效的方法呢?

这里我们可以使用优先队列,也可以说是堆。将从小文件取出来的字符串放入到小顶堆中,那堆顶的元素就是优先级队列队首的元素,就是最小字符串。将这个字符串放入到大文件中,并将其从堆中删除。然后再从小文件中取出下一个字符串,放入到堆中。循环这个过程,就可以将100个小文件中的数据依次放入到大文件中。

2、高性能定时器

场景:我们有一个定时器,其中维护了很多定时任务,每个任务都设定了一个要触发执行的时间点。每过一个很小的时间单位(比如1秒),就扫描一遍任务,如果有任务达到了预定时间,就执行。

这种任务列表的做法是比较低效的,主要有以下两点原因:

第一:未达到任务的执行时间,这样前面很多次扫描都是徒劳的。

第二:每次都要扫面整个任务列表,如果列表很大,会比较耗时。

针对上述问题,我们可以使用优先级队列来解决。我们按照任务设定的执行时间,将任务存储在优先级队列中,队列首部(小顶堆堆顶)存储的是最先执行的任务。

这样定时器就不需要每隔1秒就扫描一遍任务列表了。它拿队首任务的执行时间点与当前时间点相减,得到一个时间间隔T。

T就是从当前时间开始,需要等待多久,才会有第一个任务需要被执行。定时器在设定T秒之后,再来执行任务。当T秒过去之后,定时器取优先级队列中队首的任务执行。然后再计算新的队首任务的执行时间与当前时间的差值,这个值就是定时器执行下一个任务所需要等待的时间。

这样定时器就不同每次都间隔1秒轮询一次了,也不用变量整个任务列表,性能也随之提高了。

 

二、利用堆求Top K

求Top k 的问题,可以分为两类,一类是针对静态数据集合(数据集合事先确定,不会再变)。另一类是针对动态数据集合(集合事先不确定,有动态数据加入)。

对于静态数据来说,如何在一个包含n个数据的数组中,查找前K大的数据呢?我们可以维护一个大小为K的小顶堆,顺序遍历数组,从数组中取出数据与堆顶数据比较,如果比堆顶数据大,我们就把堆顶元素删除,并且将这个元素插入到堆中。如果比堆顶元素小,就不处理。继续遍历数组。等数组中的数据都遍历完后,堆中的数据就是前K大数据了。

对于动态数据来说,我们可以一直维护一个大小为K的小顶堆,当有数据被添加到集合中时,我们就拿它与堆顶元素对比,如果比堆顶元素大,就删除堆顶元素,并且吧这个元素插入到堆中,如果比堆顶元素小,则不做处理。这样,无论任何时候需要查询当前的前K大数据,都可以立即返回。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值