二叉堆的性質(以最小堆爲例)
- 每個子節點必須小於等於根節點
- 堆結構必須是一顆滿二叉樹
應用
- 優先隊列
- 預排序
Java實現
package mairuis.algorithm.heap;
/**
* 最小堆
* 性質:
* 1.每個子節點都小於等於其父節點
*
* @author Mairuis
* @date 2019/5/23
*/
public class MinHeap<T extends Comparable<T>> {
private Comparable[] array;
private int size;
public MinHeap(int size) {
this.array = new Comparable[size];
}
public MinHeap(Comparable[] array) {
this.array = array;
this.size = array.length;
}
public void insert(T element) {
//在尾部插入然後上浮該節點
this.set(size + 1, element);
this.size += 1;
this.swim(size);
}
public T getMin() {
return (T) array[0];
}
public void deleteMin() {
//刪除根節點,將最右邊的節點賦值到根節點
this.swap(1, size);
this.set(size, null);
size -= 1;
//下沉該節點維護堆的性質
this.sink(1);
}
private void set(int index, T v) {
array[index - 1] = v;
}
private void swim(int node) {
int x = node;
int parent = node >> 1;
//判斷1:如果是根節點 node >> 1必定爲0,parent != 0 以此實現終止
//判斷2:比較該節點與父節點,如果小於父節點則交換,維護性質
while (parent != 0 && compare(x, parent)) {
swap(x, parent);
x = parent;
parent = parent >> 1;
}
}
private void sink(int node) {
int least = node, root = node;
//如果不是根節點則交換,然後遞歸的維護下一棵樹
while (root <= size) {
//找到樹中最大的節點
int left = root << 1, right = (root << 1) + 1;
if (left <= size && compare(left, root)) {
least = left;
}
if (right <= size && compare(right, least)) {
least = right;
}
if (least != root) {
//將樹中最小的節點與根交換
swap(root, least);
//循環維護下一棵樹
root = least;
} else {
break;
}
}
}
/**
* 構建一個堆
*
* @param array
* @param <T>
* @return
*/
public static <T extends Comparable<T>> MinHeap<T> buildHeap(Comparable<T>[] array) {
MinHeap<T> heap = new MinHeap<>(array);
//從size除以2開始,篩選掉葉子節點,然後從下往上遞歸的維護每棵樹的堆性質
for (int i = heap.size >> 1; i > 0; i -= 1) {
heap.sink(i);
}
return heap;
}
/**
* 堆排序
*
* @param array
* @param <T>
* @return
*/
public static <T extends Comparable<T>> T[] heapSort(T[] array) {
MinHeap<T> heap = buildHeap(array);
for (int i = heap.size; i > 1; i -= 1) {
//將最小元素和最後一個元素交換位置
heap.swap(1, i);
//維護size字段,以保證最小元素在堆外
heap.size -= 1;
//將新的根下沉維護堆性質
heap.sink(1);
}
return (T[]) heap.array;
}
private boolean compare(int a, int b) {
return less(a, b);
}
private boolean less(int a, int b) {
return array[a - 1].compareTo(array[b - 1]) < 0;
}
private void swap(int a, int b) {
Comparable temp = array[a - 1];
array[a - 1] = array[b - 1];
array[b - 1] = temp;
}
public static void main(String[] e) {
// MinHeap<Integer> heap = new MinHeap<>(1000);
// int[] array = Sort.generalIntegers(1000);
// for (int i = 0; i < array.length; i++) {
// heap.insert(array[i]);
// }
// for (int i = 0; i < heap.size; i++) {
// System.out.println(heap.getMin());
// heap.deleteMin();
// }
// Integer[] data = new Integer[]{1, 3, 2, 5, 4};
// MinHeap<Integer> heap = buildHeap(data);
// System.out.println(heap.getMin());
// heap.deleteMin();
// System.out.println(heap.getMin());
// heap.deleteMin();
// System.out.println(heap.getMin());
// heap.deleteMin();
// System.out.println(heap.getMin());
// heap.deleteMin();
// System.out.println(heap.getMin());
// heap.deleteMin();
//
// Integer[] array = heapSort(new Integer[]{2, 1, 3, 4, 5});
// for (int i = 0; i < array.length; i++) {
// System.out.println(array[i]);
// }
}
}