当前位置: 首页 > article >正文

什么是堆?

堆(Heap):堆可以看做是一颗用数组实现的二叉树,所以它没有使用父指针或者子指针。堆根据“堆属性”来排序,“堆属性”决定了树中节点的位置。

堆的特性

1.堆是完全二叉树,除了树的最后一层节点不需要是满的,其它的每一层从左到右都是满的,如果最后一层节点不是满的,那么要求左满右不满。

2.它通常用数组来实现

具体方法就是将二叉树的节点按照层级顺序放入数组中,根结点在位置1,它的子节点在位置2和3,而子节点的子节点则分别在位置4、5、6和7,以此类推。

比如,一个节点的位置为k,则它的父节点的位置为k/2,而它的两个子节点的位置分别为2k和2k+1。这样,在不使用指针的情况下,可以通过数组的索引在树中上下移动:向上一层就令k为k/2,向下一层就令k等于2k或者2k+1.

insert插入方法的实现

由于堆是用数组完成数据元素的存储,由于数组的底层是一串联系的内存地址,所以从数组索引依次往后存放数据,但堆中的元素的顺序是有要求的,每一个结点的数据要大于等于它的两个子节点的数据(注意这点和树的方式不同),所以每次插入一个元素,都会使得堆中的数据顺序变乱,这个时候就需要额外的方法将刚插入的数据放入和合适的位置。

所以,如果往堆中插入新元素,我们只需要不断的比较新节点k和它的父节点k/2的大小,然后根据结果完成元素的交换,来实现堆的有序调整。

代码实现:

//判断堆中索引i处的元素是否小于索引j处的元素
    private boolean less(int i,int j){
        return items[i].compareTo(items[j])<0; //i如果小于j compaerto结果就为负数 --那么就返回true
    }

    //交换堆中的i索引和j索引处的值
    private void exchange(int i,int j){
        T temp=items[i];
        items[i]=items[j];
        items[j]=temp;
    }

    /**
     * 插入元素方法
     */
    public void insert(T t){
        items[++N]=t; //先++的原因是 此处数组索引0处 不存储元素 从索引1开始
        swim(N);
    }


    /**
     * 元素浮动方法
     * 时元素上浮到合适的位置
     */
    public void swim(int k){

        while (k>1){//索引1表示根节点  如果浮动到根节点 那么就不需要再浮动了
            if (less(k/2,k)){ //如果插入元素比父节点大那么就需要交换
                //父节点比子节点小 那么就需要交换
                exchange(k/2,k);
            }
            k=k/2; //然后使k上浮一层 进入下一次判断
        }
    }

deleteMax删除最大值方法的实现
由堆的特性可以知道,索引1处的元素,也就是根节点就是最大的元素,当我们把根节点的元素删除后,需要有一个新的根节点出现,这时候可以暂时把堆中的最后一个元素放到索引1处暂时充当根节点,但是这样有可能不满足堆的有序性要求,这时候就需要通过元素下沉让新的根节点放入到合适的位置。

image.png

image.png

image.png

image.png


所以删除最大元素后,只需要将最后一个元素放到索引1处,并不断拿当前节点k与它的子节点2k和2k+1比较,然后与较大者交换位置,即可完成堆的有序性调整。
代码实现:


    /**
     * 删除最大值  也就是根节点
     */
    public T deleteMax(){
        T max=items[1];  //索引1处为根节点

        exchange(1,N); //索引1根节点  与最后一个节点交换

        items[N]=null;

        N--;
        slink(1);
        return max;
    }

    /**
     * 元素下沉
     *
     */
    public void slink(int k){

        while (2*k<=N){ //当2*k>N时 就表示该k节点没有子节点了 跳出循环
            int max; //找到两个子节点中最大的
            if (2*k+1<=N){ //如果存在右子节点
                if (less(2*k,2*k+1)){//比较两个子节点
                    max=2*k+1;
                }else {
                    max=2*k;
                }
            }else { //如果不存在右子节点 那么只有左子结点的情况
                max=2*k;
            }
            //到此两个子节点中的较大者已经比较出 然后将将其比较 如果需要交换的节点比较大者要大 那么就可以结束循环
            if (!less(k,max)){
                return;
            }
            //如果当前节点 比大子节点小 那么就进行交换
            exchange(k,max);
            k=max;
        }
    }

测试结果:

public static void main(String[] args) {
        Heap<String> heap = new Heap<String>(20);
        heap.insert("A");
        heap.insert("B");
        heap.insert("C");
        heap.insert("D");
        heap.insert("E");
        heap.insert("F");
        heap.insert("G");
//        heap.insert("A");
//        heap.insert("T");
//        heap.insert("P");
//        heap.insert("R");
        String del;
        while((del=heap.deleteMax())!=null){
            System.out.print(del+",");
        }
    }
//运行结果
G,F,E,D,C,B,A,


http://www.kler.cn/a/416501.html

相关文章:

  • 阿里云服务器(centos7.6)部署前后端分离项目(MAC环境)
  • 【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-39
  • 凭借 SpringBoot 构建新冠密接者跟踪系统:快速开发与部署优势凸显
  • linux 文件权限,修改权限,c库调用
  • 现代应用程序中基于 Cell 架构的安全防护之道
  • 使用 Python 剪辑视频的播放速度
  • Redis的基本使用命令(GET,SET,KEYS,EXISTS,DEL,EXPIRE,TTL,TYPE)
  • ubuntu20配置mysql注意事项
  • 【Linux】nvidia-smi输出参数详解
  • Mac配置和启动 Tomcat
  • MySQL 查询 执行顺序
  • Node.js:开发和生产之间的区别
  • 中国前首富胡志标亮相创客匠人盛会,点燃创始人 IP 新思维火花
  • javaweb-day01-html和css初识
  • Jmeter进阶篇(28)结合AI做性能测试:开启性能测试自动化新篇章
  • 使用postcss动态设置fontsize,刷新时出现极小页面的问题
  • Libevent库-http通信不同请求方式的处理
  • 哪些行业对六西格玛管理方法的需求较大?
  • 基于若依框架和Vue2 + Element-UI 实现图片上传组件的重写与优化
  • Python 3 教程第34篇(MySQL 数据库连接 - PyMySQL 驱动)
  • 表征对齐在训练DiT模型中的重要性
  • PHP ODBC:连接数据库的桥梁
  • ASP.NET Core面试题汇总
  • 首发VM手眼标定xml文件点位取出以及转其他格式
  • 【Python】深入理解Python的字符串处理与正则表达式:文本处理的核心技能
  • A054-基于Spring Boot的青年公寓服务平台