优先级队列和堆
堆的存储方式
使用数组来保存二叉树,将二叉树的层序遍历结果按顺序放入数组中。这种方式只适合保存完全二叉树,因为非完全二叉树会浪费空间。
最大堆
满足任意节点的值都大于其子树中节点的值,叫做最大堆。
向下调整建最大堆:
public static void adjustDown(int[] array,int parent,int len) {
int child = parent * 2 + 1; //左孩子
while(child < len) {
//判断是否有右孩子,并找出左右孩子的最大值的下标
if (child + 1 < len && array[child] < array[child + 1] ) {
child ++;
}
//child中存储的就是最大值的下标
if (array[child] > array[parent]) { //大堆,左右节点最大值和父节点交换
int temp = array[child];
array[child] = array[parent];
array[parent] = temp;
//交换完成后,向下调整
parent = child;
child = parent * 2 + 1;
}else {
break;
}
}
}
public static void createHeap(int[] array) {
int len = array.length;
//向下调整建堆,每次从最后一个节点的父节点开始
//len - 1 是最后一个节点的下标 (len - 1 - 1 ) / 2 就等价于 parent = (child - 1) / 2
for (int i = (len - 1 - 1) / 2; i >= 0; i--) {
adjustDown(array,i,len);
}
System.out.println(Arrays.toString(array));
}
最小堆
满足任意节点的值都小于其子树中节点的值,叫做最小堆。
类似于最大堆,使用向下调整建最小堆,只是子结点中取最小,小于父节点则交换
public static void adjustDown(int[] array,int parent,int len) {
int child = parent * 2 + 1;
while(child < len) {
if (child + 1 < len && array[child + 1] < array[child ] ) { //左右节点取最小
child ++;
}
if (array[child] < array[parent]) { //小于父节点才交换
int temp = array[child];
array[child] = array[parent];
array[parent] = temp;
parent = child;
child = parent * 2 + 1;
}else {
break;
}
}
}
堆排序
升序建最大堆,降序建最小堆
以升序为例:
public static void heapSort(int[] array) {
if (array.length == 0) return;
createHeap(array); //求升序,建最大堆
int len = array.length - 1;
while(len > 0) {
int temp = array[0];
array[0] = array[len];
array[len] = temp;
//交换之后向下调整
adjustDown(array,0,len);
len--;
}
System.out.println(Arrays.toString(array));
}
优先级队列
Java数据结构中的优先级队列就是堆的应用
int[] array = new int[]{25,7,12,3,83,31};
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(); //优先级队列
for (Integer i :
array) {
priorityQueue.offer(i);
}
System.out.println(priorityQueue);
//[3, 7, 12, 25, 83, 31] java中的优先级队列默认是最小堆