二叉堆本質上一種完全二叉樹,分爲:最小堆和最大堆,二叉堆的根結點叫做堆頂
最大堆:最大堆的任何一個父節點的值都大於或等於他的左右節點的值,最大堆的堆頂是整個堆中最大元素
最小堆:最小堆的任何一個父節點的值都小於或等於他的左右節點的值,最小堆的堆頂是這個堆中最小元素
二叉堆的幾種操作:
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));
}
}