Java中堆的底层结构实现

堆的特性:

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,如有不正确的地方,可以在下方留言指正,谢谢。与各位CSDN的伙伴们共勉,每天记录一点点,每天进步一点点。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值