第五章 优先队列(堆)排序
优先队列是对Queue的一种优化方案。
java标准库中实现Queue的是LinkedList.它只能解决先进先出的排队操作。它是按入队时间的先后顺序进行存储。而优先队列是按优先级的顺序进行存储。
在现实生活中也很常见,比如火车站买票,军人优先、有特殊情况的客人优先。也就是说不按你的时间顺序,而是客人的优先级别。
优先队列,也就可以称为最大堆或最小堆,具体看我们的实现。java标准库java.util.PriortyQueue实现的是最小堆。
一、基本结构
它是一种完全二叉树,可以不是满的二叉树,但如果不满,只能是最后一层最从左往右,不能跳节点。
二叉堆,我们所说的二叉堆,有两个特性,
1)父节点大于等于它的子节点。
2)它是一个最大堆。(不过我们也可以做出来个最小堆)
3)节点的大小,和它所处是的层给是没有联系的。
二、具体实现
我们先现,用数据可以很好的表示二叉堆的数据结构。
如果从0开始,也可以这么表示:
- //以0为根,左节点索引位置
private int leftChild(int index) {
return 2 * index + 1;
}
- //以0为根,右节点索引位置
private int rightChild(int index) {
return 2 * index + 2;
}
- //得到父节点的索引位置
private int parent(int index) {
if (index == 0) {
return 0;
} else {
return (index - 1) / 2;
}
}
1、添加一个节点(元素上浮操作)
1)按newVal插入到最后一个索引位置。
2)size ++
2)依次和它的父节点进行比较。如果小于父节点的值,那么进行值交换。直到根节点的位置索引位置。
代码如下:
public void add(T value) {
data.add(data.size(), value);
siftUp(data.size() - 1);
}
//上浮操作
private void siftUp(int index) {
while (index > 0) {
T parentVal = data.get(parent(index));
T currentVal = data.get(index);
if (currentVal.compareTo(parentVal) < 0) {
data.swap(index, parent(index));
} else {
break;
}
index = parent(index);
}
}
2、删除最小元素
1)先最后的索引位置元素的值,赋值给根节点(索引为0的位置)。【不是删除根节点,是值的覆盖】
2)size -- 也没有把最后一个索引位置的元素删除。只是size上面不进行关联,再也找不到这个索引位置而已
3)从根节点开始进行下浮。
4)依次进行:节点的值与左右子节点中最小值进行比较,如果左右子节点中最小值小于该节点的值,则进行下浮操作。交互元素的值。直到叶子节点为止。
代码如下:
public T remove() {
if (data.isEmpty()) {
return null;
}
T popVal = data.get(0);
data.swap(0, data.size() - 1);
data.remove(data.size() - 1);
siftDown(0);
return popVal;
}
private void siftDown(int k) {
while (leftChild(k) < data.size()) {
int j = leftChild(k);
if (j + 1 < data.size() && data.get(j + 1).compareTo(data.get(j)) < 0) {
j++;
}
if (data.get(k).compareTo(data.get(j)) < 0) {
break;
}
data.swap(k, j);
k = j;
}
}
三、构造一个优先队列
一个普通数组变成优先队列的过程如下:
public MyPriorityQueue(T[] arr) {
this.data = new MyArrayList<T>(arr);
for (int i = parent(data.size() - 1); i >= 0; i--) {
siftDown(i);
}
}
四、排序实现
放到第六章排序中实现
PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(); //小顶堆,默认容量为11
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(11,new Comparator<Integer>(){ //大顶堆,容量11
@Override
public int compare(Integer i1,Integer i2){
return i2-i1;
}
});