二叉堆的性质(以最小堆为例)
- 每个子节点必须小于等于根节点
- 堆结构必须是一颗满二叉树
应用
- 优先队列
- 预排序
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]);
// }
}
}