前言
1、堆是完全二叉树,除了树的最后一层结点不需要是满的,其他的每一层从左到右都是满的,如果最后一层不是满的,则要求左满右不满。
2、如果一个结点的位置为k,则它的父节点的位置为k/2,而它的两个子结点的位置则分别为2k和2k+1。
3、每个结点都大于它的两个子结点。而两个子结点的大小顺序并没有做规定。
代码示例
public class Heap<T extends Comparable> {
T[] items ;
int size;
public Heap(int capacity) {
items = (T[]) new Comparable[capacity];
size = 0;
}
//判断堆中索引i处的元素是否小于索引j的元素
private boolean less(int i,int j){
return items[i].compareTo(items[j])<0;
}
//交换堆中索引i和索引j的元素
private void exch(int i,int j){
T temp = items[i];
items[i] = items[j];
items[j] = temp;
}
//往堆中插入一个元素
public void insert(T t){
items[++size] = t;
swim(size);
}
//使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置
private void swim(int k){
while (k>=2){
if (!less(k/2,k)){//如果父结点比当前结点大,则结束循环
break;
}
exch(k/2,k);
k= k/2;
}
}
//删除堆中最大的元素,并返回这个最大的元素
public T delMax(){
if (size==0){
return null;
}
//把最大元素与最末元素交换
exch(1,size);
//把最末元素进行删除
T delElement = items[size];
items[size] = null;
//把跟结点下沉
size--;
sink(1);
return delElement;
}
//使用下沉算法,使索引k处的元素能在堆中处于一个正确的位置
private void sink(int k){
while (2*k<=size){
//找出子结点中大的结点索引
int max;
if (2*k+1>size){ //如果右结点等于null,则max等左结点
max = 2*k;
}else {
max = less(2*k,2*k+1)?(2*k+1):(2*k);
}
//比较k索引处的元素与max中元素,
if (!less(k,max)){//如果k索引元素比max大,则结束循环
break;
}
exch(k,max);
k = max;
}
}
}
测试:
public static void main(String[] args) {
Heap<Integer> heap = new Heap<>(10);
heap.insert(8);
heap.insert(7);
heap.insert(6);
heap.insert(5);
heap.insert(12);
heap.insert(18);
Integer result ;
while ((result=heap.delMax())!=null){
System.out.print(result+" ");
}
}
输出结果为:18 12 8 7 6 5
符合预期