一、堆
什么是堆?
用完全二叉树表示的优先队列
优先队列:取出元素的顺序依据优先级的大小 处理的问题思想类似于CPU处理任务时的优先级
堆的特性:1.结构性 2.有序性
如果最小键值元素拥有最高的优先级,那么这种优先队列叫作升序优先队列(即总是先删除最小的元素),类似的,如果最大键值元素拥有最高的优先级,那么这种优先队列叫作降序优先队列(即总是先删除最大的元素)。一般默认的优先队列为升序优先队列。
1.1堆的一些基本操作
插入insert:插入元素,并以一定的顺序排序。类似队列里的入队enqueue操作
删除deleteMin/deleteMax:删除最小值或者最大值元素。类似队列里的出队dequeue操作
1.2堆的应用
- 数据压缩:哈夫曼编码算法;
- 最短路径算法:Dijkstra算法;
- 最小生成树算法:Prim算法;
- 事件驱动仿真:顾客排队算法;
- 选择问题:查找第k个最小元素
二、二叉堆
二叉堆就是每个结点最多有两个孩子,所以也有d堆对应的就是最多有d个孩子
用数组表示堆是一个比较常规且方便的方法。
一个结点对应的数组索引是i,它的左子结点就是i*2,右子结点就是i*2+1,它的父节点就是i整除2
2.1向堆中添加元素和Percolate Up(上滤)
当插入一个元素到堆中时,它可能不满足堆的性质,在这种情况下,需要调整堆中元素的位置使之重新变成堆,这个过程称为堆化(heapifying);在最大堆中,要堆化一个元素,需要找到它的父亲结点,如果不满足堆的基本性质则交换两个元素的位置,重复该过程直到每个结点都满足堆的性质为止
2.2取出堆中的最大元素和Percolate Down(下沉)
取出堆中的最大元素(堆顶元素)将变得容易,不过这里运用到一个小技巧,就是用最后一个元素替换掉栈顶元素,然后把最后一个元素删除掉,这样一来元素的总个数也满足条件,然后只需要把栈顶元素依次往下调整就好了,这个操作就叫做Percolate Down(下沉)
三、Java中的PriorityQueue
在Java中也实现了自己的优先队列PriorityQueue
,与我们自己写的不同之处在于,Java中内置的为最小堆,然后就是一些函数名不一样,底层还是维护了一个Object类型的数组,另外如果想要把最小堆变成最大堆可以给PriorityQueue传入自己的比较器,例如:
// 默认为最小堆
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.add(5);
pq.add(2);
pq.add(1);
pq.add(10);
pq.add(3);
while (!pq.isEmpty()) {
System.out.println(pq.poll() + ", ");
}
System.out.println();
System.out.println("————————————————————————");
// 使用Lambda表达式传入自己的比较器转换成最大堆
PriorityQueue<Integer> pq2 = new PriorityQueue<>((a, b) -> b - a);
pq2.add(5);
pq2.add(2);
pq2.add(1);
pq2.add(10);
pq2.add(3);
while (!pq2.isEmpty()) {
System.out.println(pq2.poll() + ", ");
}