堆的特性:
1、它是完全二叉树,除了树的最后一层结点不需要是满的,其它的每一层从左到右都是满的,如果最后一层结点不 是满的,那么要求左满右不满。
2、通常用数组来实现,将二叉树的结点按照层级顺序放入数组中,根结点在位置1,它的子结点在位置2和3,而子结点的子 结点则分别在位置4,5,6和7,以此类推。
如果一个结点在数组中的索引为k,则它的父结点的索引为k/2,它的左右子结点的索引分别为2k和2k+1。这样,在不使用指针的情况下,我们可以通过计算元素在数组中的索引来实现结点在树中上下移动
3、每个结点的值都大于等于它的两个子结点。
堆的API设计
堆的代码实现
/**
* @author: xuzhilei6656
* @create: 2021-12-10 11:26
* @description: 堆的实现
**/
public class Heap<T extends Comparable<T>> {
//存储堆中的元素
private final T[] items;
//记录堆中元素个数
private int number;
//构造方法
public Heap(int capacity) {
this.items = (T[]) new Comparable[capacity + 1];
this.number = 0;
}
//判断堆中索引i处的值是否小于索引j处的值
public boolean less(int i, int j) {
return items[i].compareTo(items[j]) < 0;
}
//交换堆中i索引和j索引的值
public void exch(int i, int j) {
T temp = items[i];
items[i] = items[j];
items[j] = temp;
}
//往队中插入一个元素
public void insert(T t){
//往数组中添加一个元素
items[++number] = t;
//元素上浮
swim(number);
}
//使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置
private void swim(int k) {
while (k > 1){
//如果k结点的值大于父结点的值,则交换
if (less(k/2,k)){
exch(k/2,k);
}
//变换k
k = k/2;
}
}
//删除堆中最大的元素,并返回这个最大的元素
public T delMax(){
//堆中第一个元素即为最大的元素
T max = items[1];
//交换索引1处和最大索引处的元素,让完全二叉树最后一个元素变为临时根结点
//items[1] = items[number]; //此方式也可行
exch(1,number);
//删除掉最大索引处的值
items[number] = null;
number--;
//使用下沉算法,让临时根结点处于合适的位置
sink(1);
return max;
}
//使用下沉算法,让索引k处的元素处于合适的位置
private void sink(int k) {
//循环比较索引k处元素与其左右子结点的元素大小,让k索引处元素与较大者交换位置
while (2*k<=number){
//记录较大者元素所在的索引值
int max;
//如果存在右子结点
if (2*k+1<=number){
//比较左右子结点元素大小,将较大者的索引给max
if (less(2*k,2*k+1)){
max = 2*k+1;
}else {
max = 2*k;
}
}else {
max = 2*k;
}
//比较当前索引k处元素与索引max处元素大小
if (!less(k,max)){
break;
}
//交换索引k与索引max处的元素位置
exch(k,max);
//变换k的值
k = max;
}
}
//获取堆中元素个数
public int size(){
return number;
}
//判断堆是否为空
public boolean isEmpty(){
return number==0;
}
public static void main(String[] args) {
Heap<String> heap = new Heap<>(20);
heap.insert("A");
heap.insert("B");
heap.insert("C");
heap.insert("D");
heap.insert("E");
heap.insert("F");
heap.insert("G");
String max;
while ((max = heap.delMax())!=null){
System.out.println(max);
}
}
}
测试结果
以上仅个人学习时随手敲的demo,如有不正确的地方,可以在下方留言指正,谢谢。