堆(Heap)
基础表示
- 二叉堆是一颗完全二叉树
- 什么是完全二叉树?
- 将数据一层一层的排列成树的形状,按照树从左到右的顺序,直到放不下为止
- 也就是说可以如果有空缺的元素,必须是在树的右下方
性质
- 最大堆:堆中某个节点的值总是不大于其父节点的值(相应也有最小堆)
- 节点的大小与层次无关
动态数组表示最大堆
1 | public class MaxHeap<E extends Comparable<E>> { |
添加元素和Sift up
1 | // 向堆中添加元素 |
取出元素和Sift down
1 | // 看堆中的最大元素 |
Replace
- 取出最大元素后,放入一个新元素
- 实现1:先extractMax ,再add,两次O(logn)操作
- 实现2:直接将堆顶元素替换后,Sift down ,一次O(logn)操作
1 | // 查看堆中最大元素 |
Heapify
将任意数组整理成堆的形状,不需要单独写成一个函数,可以单独放在一个新的堆的构造函数中
从最后一个非叶子节点进行操作
- 在自制的 ArrayList 中,增加构造函数
1 | public Array(E[] arr){ |
###复杂度
- add 和 extractMax 时间复杂度都是 O(logn)
- 因为堆是一个完全二叉树,所以永远都不会退化为链表
优先队列(Priority-Queue)
- 普通队列:先进先出,后进后出
- 优先队列:出对顺序与进队顺序无关,和优先级相关
应用场景
- 医院:患者会动态增加,在其中选择优先级高的进行就诊
- 游戏AI:选择优先级高的玩家进行攻击
代码实现
- 和普通队列一样,继承队列接口,不过确认队首和出队的操作会有变化
- 实现方式有普通线性结构、顺序线性结构、堆三种实现方,堆最高效
1 | // 堆实现优先队列 |
比较器
自制优先队列
- 自制的优先队列内置的是最大堆,如果遇到取出某些问题需要内置最小堆怎么办?
- 其实 最大 和 最小 是可以相互转换的, 那么我们先要创建一个频率类,
1 | private class Freq implements Comparable<Freq>{ |
Java优先队列
- 内置的优先队列比较高级,可以使用比较器
- 当然也可以直接将比较器匿名内部类的形式