-----------------siwuxie095
和堆相关的问题
(1)使用堆实现优先队列:动态选择优先级最高的任务执行
完全可以使用堆当做一个优先队列,对于系统的若干个进程来讲,
每次都用堆找到优先级最高的任务进行执行,而如果系统来了新
的任务,只要把这个任务插入到堆中即可,如果操作系统要修改
任务的优先级,也是可以实现的
(2)游戏中角色的人工智能
游戏中的某个角色要自动选择攻击范围里的敌人进行攻击,它要
根据这些敌人的属性选择最需要攻击的那个敌人进行攻击。在这
个过程中,就可以把在攻击范围中的敌人放进一个堆中,由堆来
选出每次要攻击哪个敌人。如果有新的敌人进入了攻击范围,就
把新的敌人插入到堆中即可
不难看出,所谓很智能的决策过程,其实背后就是一个数据结构,
使用一个堆就可以表现出不错的智能来
(3)在 1000000 个元素中选出前 100 名
如果将这一百万个元素都排一遍序,就是 n*lgn 这样的复杂度,
但完全可以使用一个最小堆,保持最小堆中元素的数量永远是
小于等于 100 的
这样一来,当把前 100 个元素放进这个最小堆之后,每次新放
入一个元素,就会将堆中当前最小的元素移出去,这样就维持
整个堆一直保持着 100 个元素。当把这一百万个元素全都遍历
完成后,最终这个最小堆中所存放的所有元素,就是这一百万
个元素中的前一百名
这样,算法的时间复杂度就变成了 n*lgm 级别的
(4)多路归并排序(k 路归并排序):可以使用堆实现多路的归并
普通归并排序:在归并排序的过程将当前要处理的数组,一分为二,
分别排序以后再进行归并。归并时,每次只要比较两个子数组的第
一个元素的大小即可
多路归并排序:在归并排序的过程中将整个数组分成两个以上的子
数组,之后再进行归并
假如分成了四部分,那么在归并的过程中,每次就要比较四个元素
的大小关系,在比较四个元素的大小关系时怎么比更快呢?
可以逐一比较,不过一个更好的方法是将这四个元素,放进一个最
小堆中,每次从堆中推出一个当前最小的元素,推出的这个元素属
于哪个子数组,就从这个子数组中再拿出一个新的元素添加进堆中
更一般的,对于一个有 n 个元素的数组,做一个 k 路的归并排序
k 路归并排序的 k 的选择,实际上是一个性能的平衡。k 越大,层
数就会越小,但在每次归并的过程中需要比较的元素也就越多
「k 随测试用例的不同而变化」
如果 n 个元素的数组要做 n 路的归并排序,那么归并的过程只需
要递归一层即可
在这一层中每一个子数组中都只有一个元素,剩下的事情就是使
用一个堆,将这 n 个只有一个元素的子数组进行排序
此时,归并排序退化成了堆排序
(5)多叉堆(d 叉堆)
二叉堆是每一个节点最多只能有两个孩子,那么 d 叉堆就是每个
节点最多只能有 d 个孩子
d 叉堆的 d 的选择,也是一个性能上的平衡。d 越大,层数越小,
但在 Shift Up 和 Shift Down 的过程中,需要比较的元素也就越
多
「d 随测试用例的不同而变化」
显然,二叉堆最经典,且在一般的任务中,二叉堆足以应付
(6)堆的实现细节优化
1)Shift Up 和 Shift Down 的过程中,使用赋值操作代替交换操作
2)索引从 0 开始
3)没有 capacity 的限制,动态调整堆中数组的大小
注意:当 capacity 不够用了,重新申请空间的过程一定是复杂度为
O(n) 级别的算法,且要申请 2*capacity 这么大的空间
这样一来,从平均效率来讲,堆中的所有的操作依然是保持不变的,
不会因为这个动态的调整,而对用户使用这个堆的性能产生巨大的
影响
(7)最大最小队列
最大堆和最小堆所形成的这个优先队列,要么可以非常容易的找到
所有元素中最大的元素,要么可以非常容易的找到所有元素中最小
的元素
其实可以设计一个类,叫做 最大最小队列,既能非常快的找到最大
的元素,又能非常快的找到最小的元素
具体实现:可以在这个数据结构中,既放一个最大堆,又放一个最
小堆,两个堆同时维护同一组数据
(8)二项堆、斐波那契堆
其实堆还有很多的变种,如:二项堆、斐波那契堆
这些堆,或者它们的操作速度更快一些,或者在一些特殊的场合,
对于一些特殊的操作有更高的性能优势
【made by siwuxie095】