批量建堆(二叉堆【完全二叉堆】)~~批量建堆

简介: 批量建堆

批量建堆


 

1,逻辑:局部建立堆---》整体建立堆

2,其实就是一个调整范围的确定 + 考虑当前结点的身份(作为子结点或父结点)而已。

■ 上滤(自上而下的上滤【本质就是添加】)—----当前结点作为子节点,考虑它作为子结点在当前位置是否合适。

■ 下滤(自下而上的下滤【本质就是删除】)------当前结点作为父结点,考虑它作为父结点在当前位置是否合适。

 

❀ 上滤建立堆-----逻辑就是添加时的上滤操作-是添加到数组的最后一个位置,然后不断地往上比(比较的终点是根),当前结点与它的父结点比较【直到找到合适位置

❀ 下滤建立堆----逻辑就是符合删除操作~从第一个非叶子结点开始(比较的终点是根),当前结点不断地与它的最大子结点比较【直到找到合适位置

 

 

最大堆----批量建堆-效率对比:上滤与下滤比较----同线比较

例如:拿1号线作比较,可以看到上滤与下滤比较:

上滤可能移动的结点比较多(往上跑的结点数量比较多),

下滤可能移动的结点比较少(往下跑的结点数量比较少)


18.png


19.png



● 添加代码(咱使用的数据结构是数组):


@Override
    public void add(E element) {
        //检查元素是否具有可比较性【排除null】
        elementNotFoundCheck(element);
        // 扩容检查、扩容操作
        ensureCapacity(size + 1);
        //按数组添加特点【每次都是添加到最后的位置,添加完数组长度++】
        elements[size++] = element;
        //维持二叉堆的特点【大根堆特点】~ 上滤
        siftUp(size -1);
    }

● 上溢代码:


/**
     * 上滤【从最后一个位置开始往上 】
     * 【插入到原逻辑的优化,插入到最后一个位置时,比较当前结点的父结点是否还是大于    * 【插入结点,若是满足,即找到合适位置,否则,当前结点的父结点要变成子结点啦,然后爬升到父结点的位置继续比较】】
     */
    private void siftUp(int index) {        
        // 插入element 随着比较不断的上移【选择一个合适的位置(插入的当前结点比父结点小)】,而是最终确定位置后,放一下]
        E element = elements[index]; 
        while (index > 0) {
            int parentIndex = (index - 1) >> 1;
            E parent = elements[parentIndex];
            if (compare(element, parent) <= 0) break;
            //让比较小的父元素放到子元素位置
            elements[index] = parent;
            // 重新赋值index
            index = parentIndex;
        }
        elements[index] = element;//找到最终的位置index
    }


● 删除代码:


@Override
    public E remove() {
        emptyCheck();//检查数组是否为空
        E root = elements[0];
        int lastIndex = --size;
        elements[0] =  elements[lastIndex];
        elements[lastIndex] = null;
        //下滤
        siftDown(0);    //根据索引进行下滤操作
        return root;
    }


● 下溢代码:


/**
     * 下滤:删除操作【从第 index 位置开始,往下】
     * 即从当前结点开始往下比(跟最大孩子结点比),直到找到合适的位置【满足 当前结点的值(作为父结点)大于子结点的值】
     * 当出现了最大子结点大于父结点时,子结点的值覆盖到父节点的位置
     * @param index
     */
    private void siftDown(int index) {
        /**
         * 非叶子结点个数: n1 + n2 = floor(n /2);【最后一个非叶子结点索引即:(size/2) - 1】
         * 叶子结点个数:n0 = floor((n + 1) /2);
         *结论:第一个叶子结点的索引就是非叶子结点的数量【从上到下,从左到右,非叶子-》叶子】
         */
//        while(index < 第一个叶子结点的索引)【即保证index 都是非叶子结点】
        int half = size >> 1;
        E element = elements[index];
        while(index < half) {
            //完全二叉树:只能有两种情况:
            //1,只有 左结点
            //2,有左,有右
            //默认假设左结点是最大结点
            int childIndex = (index << 1) + 1;//左结点的索引要注意【位移符号的书写的方向】
            E childElement = elements[childIndex];
            //rightIndex < size [说明右结点存在,处于合理区间|,即存在]
            int rightIndex = childIndex + 1;
            if(rightIndex < size
                    && compare(elements[rightIndex], childElement) > 0) {
                childIndex = rightIndex;
                childElement = elements[rightIndex];
                //优化一下代码写法:
//                childElement = elements[childIndex = rightIndex];
            }
            //用当前结点的最大子结点和当前结点进行比较【当前大的话】
            //bug:if(compare(elements[index], childElement) >= 0)
            //错误:咱是要将element 找到合适位置呀,element 是固定的呀,不是 elements[index]
            if(compare(element, childElement) >= 0) break;
            //子结点大的话
            elements[index] = childElement;
            index = childIndex;
        }
        elements[index] = element;
    }



目录
相关文章
|
9月前
|
JSON 缓存 小程序
微信小程序组件封装与复用:提升开发效率
本文深入探讨了微信小程序的组件封装与复用,涵盖组件的意义、创建步骤、属性与事件处理,并通过自定义弹窗组件的案例详细说明。组件封装能提高代码复用性、开发效率和可维护性,确保UI一致性。掌握这些技能有助于构建更高质量的小程序。
|
机器学习/深度学习 传感器 算法
【机器学习】在聚类算法中,使用曼哈顿距离和使用欧式距离有什么区别?
【5月更文挑战第12天】【机器学习】在聚类算法中,使用曼哈顿距离和使用欧式距离有什么区别?
|
人工智能 IDE 程序员
一文梳理我们是如何打造出国内领先的 AI 编程助手「通义灵码」
大语言模型的革命性突破使智能编程成为了可能,通义灵码正是基于通义大模型打造的 AI 编程助手,通过 IDE 插件的形式提供代码补全、单元测试生成等功能,能达到毫秒级的响应速度。目前,通义灵码已在阿里云内部及多家企业中应用,阿里云也在探索多智能体产品,即 AI 程序员,助力数字世界的蓬勃发展,颠覆 IT 生产力。
15746 244
|
人工智能 监控 并行计算
Stable Diffusion火影数据集训练:SwanLab可视化训练
**使用Stable Diffusion 1.5模型训练火影忍者风格的文生图模型。在22GB显存的GPU上,通过Huggingface的`lambdalabs/naruto-blip-captions`数据集进行训练,利用SwanLab进行监控。所需库包括`swanlab`, `diffusers`, `datasets`, `accelerate`, `torchvision`, `transformers`。代码、日志和更多资源可在GitHub和SwanLab找到。训练涉及数据下载、模型配置、训练过程可视化及结果评估。**
Stable Diffusion火影数据集训练:SwanLab可视化训练
基于EM期望最大化算法的GMM模型参数估计matlab仿真
此程序在MATLAB 2022a中实现了基于EM算法的GMM参数估计,用于分析由多个高斯分布组成的混合数据。程序通过迭代优化各高斯组件的权重、均值与协方差,直至收敛,并输出迭代过程的收敛曲线及最终参数估计结果。GMM假设数据由K个高斯分布混合而成,EM算法通过E步计算样本归属概率,M步更新参数,循环迭代直至收敛。
|
NoSQL 关系型数据库 数据库
数据库同步 Elasticsearch 后数据不一致,怎么办?
数据库同步 Elasticsearch 后数据不一致,怎么办?
|
弹性计算 网络安全 数据中心
阿里云VPC创建专有网络10、172和196网段选择注意事项
阿里云VPC创建专有网络10、172和196网段选择注意事项,阿里云专有网络VPC私网网段可选192.168.0.0/16、172.16.0.0/12或10.0.0.0/8,如何选择?阿里云百科来详细说下阿里云专有网络IPv4网段选择方法:
678 0
阿里云VPC创建专有网络10、172和196网段选择注意事项
|
XML 数据安全/隐私保护 数据格式
Minio出现Non-XML response from server. Response code: 400, Content-Type: text/xml; ch的解决
Minio出现Non-XML response from server. Response code: 400, Content-Type: text/xml; ch的解决
5075 0
|
存储 SQL 人工智能
MySQL监控-Datadog数据库监控调研
MySQL是最流行的数据库之一,在大多系统的后端的存储都有MySQL的身影,MySQL运行的是否健康,直接影响着整个系统的运行,数据库的瓶颈往往也是整个系统的瓶颈,其重要性不言而喻,所以对于MySQL的监控必不可少,及时发现MySQL运行中的异常,可以有效提高系统的可用性和用户体验。 本文主要介绍下MySQL如何做监控,以及对Datadog的Database Monitoring的一些简单调研。
1557 0
MySQL监控-Datadog数据库监控调研
|
SQL 存储 关系型数据库
MySQL探秘(八):InnoDB的事务
事务是数据库最为重 要的机制之一,凡是使用过数据库的人,都了解数据库的事务机制,也对ACID四个基本特性如数家珍。但是聊起事务或者ACID的底层实现原理,往往言之不详,不明所以。所以,今天我们就一起来分析和探讨InnoDB的事务机制,希望能建立起对事务底层实现原理的具体了解。