二叉堆本质上一种完全二叉树,分为:最小堆和最大堆,二叉堆的根结点叫做堆顶
最大堆:最大堆的任何一个父节点的值都大于或等于他的左右节点的值,最大堆的堆顶是整个堆中最大元素
最小堆:最小堆的任何一个父节点的值都小于或等于他的左右节点的值,最小堆的堆顶是这个堆中最小元素
二叉堆的几种操作:
1、插入节点:插入位置是完全二叉树的最后一个位置;堆的插入操作是单一节点的“上浮”,平均交换次数都是堆高度的一半,所以时间复杂度是O(logn)
2、删除节点:删除的是处于堆顶的节点;堆的删除操作是单一节点的“下沉”,平均交换次数都是堆高度的一半,所以时间复杂度是O(logn)
3、构建二叉堆:就是将一个完全无序的二叉树调整为二叉堆,本质上就是让所有非叶子结点依次“下沉”;时间复杂度是O(n)
/**
* 二叉堆构建
*/
public class Adjust {
/**
* "上浮"调整
*
* @param arr
*/
public static void upAdjust(int[] arr) {
if (arr == null) {
return;
}
int childIndex = arr.length - 1;
int parentIndex = (childIndex - 1) / 2;
//保存插入的叶子结点的值,用于最后的赋值
int temp = arr[childIndex];
while (childIndex > 0 && temp < arr[parentIndex]) {
//无须真正交换,单向赋值即可
arr[childIndex] = arr[parentIndex];
childIndex = parentIndex;
parentIndex = (parentIndex - 1) / 2;
}
arr[childIndex] = temp;
}
/**
* "下沉"调整
*
* @param arr 待调整值
* @param parentIndex 待下沉的父节点
* @param length 堆的有效大小
*/
public static void downAdjust(int[] arr, int parentIndex, int length) {
int temp = arr[parentIndex];
int childIndex = parentIndex * 2 + 1;
while (childIndex < length) {
//如果有右孩子,且右孩子小于左孩子则定位到右孩子
if (childIndex + 1 < length && arr[childIndex + 1] < arr[childIndex]) {
childIndex++;
}
//如果父节点小于任何一个孩子的值,直接退出
if (temp < arr[childIndex]) {
break;
}
//无须交换,单向赋值即可
arr[parentIndex] = arr[childIndex];
parentIndex = childIndex;
childIndex = 2 * childIndex + 1;
}
arr[parentIndex] = temp;
}
/**
* 构建堆
*
* @param arr
*/
public static void buildHeap(int[] arr) {
//从最后一个非叶子节点开始,依次做下沉操作
for (int i = (arr.length - 2) / 2; i >= 0; i--) {
downAdjust(arr, i, arr.length);
}
}
public static void main(String[] args) {
int[] arr = new int[]{1, 3, 2, 6, 5, 7, 8, 9, 10, 0};
upAdjust(arr);
System.out.println(Arrays.toString(arr));
arr = new int[]{7, 1, 3, 10, 5, 2, 8, 9, 6};
buildHeap(arr);
System.out.println(Arrays.toString(arr));
}
}