《算法之美》---二叉堆及其实现

常用数据结构与算法:二叉堆(binary heap) 一:什么是二叉堆 二:二叉堆的实现  三:使用二叉堆的几个例子 一:什么是二叉堆 1.1:二叉堆简介       二叉堆故名思议是一种特殊的堆,二叉堆具有堆的性质(父节点的键值总是大于或等于(小于或等于)任何一个子节点的键值),二叉堆又具有二叉树的性质(二叉堆是完全二叉树或者是近似完全二叉树)。当父节点的键值大于或等于(小于或等于)它的每一个子节点的键值时我们称它为最大堆(最小堆 阅读详情

二叉堆是一棵满足下列性质的完全二叉树:

1)如果某节点有孩子,则根节点的值都小于孩子节点的值。我们称之为小根堆;

2)如果某节点有孩子,则根节点的值都大于孩子节点的值。我们称之为大根堆。

这样,如果我们用一维数组a存储来存储该堆,那么具有n个节点的堆可看成是一棵按层次排列,同一层按自左向右排列的完全二叉树。显然,小根堆的根节点是最小值,大根堆的根节点是最大值,计算过程分下面两步进行:

(1)—建堆,把数组a中各个元素转变成堆;

(2)—对数组a进行排序:

         通过相继地输出根节点,产生递增(递减)序列;

         保持余下节点的堆性质。

 

在调整中保持堆性质:

以小根堆为例,假设节点a[s]的左右子树都是小根堆,而添加a[s]后不满足小根堆性质,我们的方法是从根节点出发顺着左右子树的一边逐步进行调整,调整的过程实质上是让a[s]在小根堆中下降,最终满足以s为根的子树成为小根堆。过程如下:

1)找出s节点左右子节点中权值较小者,记其位置为j;

2)比较a[j]和a[s]:若a[s]的权值小于等于a[j],则调整完毕;否则a[s]<---a[j],s<---j,继续从s出发向下调整。

调整堆的伪代码如下所示:

//从a[s]出发向下调整建堆:若a[s]的左右孩子均大于a[s],则调整完毕;

//否则,找出其中较小者,其序号记为j;a[s]和a[j]的值交换,继续由a[j]往下调整

procedure heap(s, n : longint);

Var

         i, j, k : longint;

{

         j <-- 1; k <-- a[s];   //暂存a[s],a[s]左右孩子的较小者序号初始化为1

         while j <> maxint do

         {

                   i <-- a[s]; j <-- maxint; //找出a[s]的左右孩子的较小者,其序号为j

                   if s*2<=n       //左孩子

                            then if a[s*2]<i then {i<--a[s*2]; j<--s*2;}        //顺着左孩子方向找

                   if s*2+1<=n //右孩子

                            then if a[s*2+1]<i then{i<--a[s*2+1]; j<--(s*2+1); }         //顺着右孩子方向找

                   if j<>maxint then {a[s]<--i; s<--j; } //a[s]的值调整为其左右孩子较小者,继续从a[j]往下调整

         }

         a[s]<--k; //最后位置的值调整为原子根值

}

 

下面是最小堆的一个类模板及其测试代码:

========================asce.h===========================

#include <iostream>

 

template<typename T> class MinPQ //抽象类

{

public:

    virtual int Insert(const T&)=0; //纯虚函数

    virtual int RemoveMin(T&)=0;                     

};

 

//最小堆的定义

template<typename T>

class MinHeap : public MinPQ<T>

{

public:

    MinHeap(int maxSize);

    MinHeap(T arr[], int n);

    ~MinHeap() {delete[] heap;}

   

    int Insert(const T &x);    //入队

    int RemoveMin(T &x);   //出队

    bool IsEmpty() const

    {

        return currentSize == 0;    

    }

    bool IsFull() const

    {

        return currentSize == MaxHeapSize;    

    }

 

private:

    enum{DefaultSize = 10};

    T *heap;         //存放堆的数组

    int currentSize; //当前元素个数,堆尾

    int MaxHeapSize;

    void FilterDown(int start ,int endOfHeap);

    void FilterUp(int start);

};

 

//构造函数,根据给定大小maxSize,建立堆对象

template<typename T>

MinHeap<T>::MinHeap(int maxSize)

{

    //确定堆大小

    MaxHeapSize = DefaultSize<maxSize ? maxSize : DefaultSize;

    heap = new T[MaxHeapSize];        //创建堆数组空间

    currentSize = 0;

}

 

//构造函数,根据数组建立堆对象

template<typename T>

MinHeap<T>::MinHeap(T arr[], int n)

{

    //确定堆大小

    MaxHeapSize = DefaultSize<n ? n : DefaultSize;

    heap = new T[MaxHeapSize];

    heap = arr;  //数组传送

    currentSize = n; //当前堆大小

    int currentPos = (currentSize-1)/2; //最后的非叶子节点 

    while(currentPos >= 0)

    {

        //从上到下逐步扩大,形成堆

        FilterDown(currentPos, currentSize-1);

        //从currentPos开始到currentSize为止,调整

        currentPos--;                

    }

}

 

//最小堆的向下调整算法

template<typename T>

void MinHeap<T>::FilterDown(int start, int endOfHeap)

{

    int i = start;

    int j = 2*i + 1; //j是的左孩子

    T temp = heap[i];

    while(j <= endOfHeap)

    {

        if(j < endOfHeap && heap[j] > heap[j+1])

            j++; //左右两孩子中选择较小者,即heap[j+1]

        if(temp <= heap[j])

            break; //调整结束

        else

        {

            heap[i] = heap[j];

            i = j;

            j = 2*j + 1;   

        }       

    }   

    heap[i] = temp;

}

 

//堆的插入操作

template<typename T>

int MinHeap<T>::Insert(const T &x)

{

    //在堆中插入新元素x

    if(currentSize == MaxHeapSize) //堆满

    {

        std::cout<<"堆已满"<<std::endl;

        return 0;              

    }   

    heap[currentSize] = x; //插在表尾

    FilterUp(currentSize); //向上调整堆

    currentSize++;       //堆元素增1

    return 1;

}

 

//最小堆的向上调整算法(堆已建好,用于插入)

template<typename T>

void MinHeap<T>::FilterUp(int start)

{

    //从start开始向上直到0,调整堆

    int j = start;

    int i = (j-1)/2; //i是j的双亲

    T temp = heap[j];

    while(j > 0)

    {

        if(heap[i] <= temp)

            break;

        else

        {

            heap[j] = heap[i];

            j = i;

            i = (i-1)/2;   

        }       

    }    

    heap[j] = temp;

}

 

 

//最小堆的删除算法(出堆),输入参数x用于接收出堆的元素

//不断调用RemoveMin函数输出x就相当于升序排序了

template<typename T>

int MinHeap<T>::RemoveMin(T &x)

{

    if(currentSize <= 0)

    {

        std::cout<<"堆已空"<<std::endl;

        return 0;              

    }

    x = heap[0]; //最小元素heap[0]出队列

    heap[0] = heap[currentSize-1]; //用最后元素填补

    currentSize--;

    //从0号位置开始自上向下调整为最小堆

    FilterDown(0, currentSize-1);

   

    return 1;

}

 

=====================测试代码TestCase.cpp======================

#include "asce.h"

 

int main()

{

    int arr[] = {1, 4, 34, 6, 43, 10,9};

    MinHeap<int> ace(arr, 8);

    int show = 0;

    for(int i=0; i<7; i++)

    {

        ace.RemoveMin(show);

        std::cout<<show<<std::endl;               

    }

    system("pause");

    return 0;

}

 

二叉堆建堆的优化算法原理图解及代码实现 二叉堆的简单建堆方法 有时二叉堆是由一些项的初始结合构造而得。这种构造方法以N项作为输入。 最浅显的建堆方式,可以通过N个连续的insert操作(Williams’ method)来完成,由于每个insert将花费O(logN)时间,因此建堆的最坏运行时间是O(NlogN)。但是这种建堆的方式并不是最优算法。 二叉堆的优化建堆方法 更快速算法是,将N项以任意顺序放入树中,保持结构特性。 阅读详情

相关推荐

数据结构与算法——优先队列类的C++实现(二叉堆)

优先队列类的C++实现(二叉堆) ;二叉堆与二叉查找树类似,二叉树有两个性质:结构性质和堆序性质。 那些运行时间短的进程需要比较高的优先权,同样,那些比较重要的进程也需要比较高的优先权。这种特殊的应用需要一种特殊的队列-----优先队列。可以用二叉堆实现优先队列。

Be The Best! 3321

dijkstra迪杰斯特算法邻接表加二叉堆实现python版

dijkstra迪杰斯特算法 需要知道的点: 1、属于贪心算法 2、得到一点到其他各点的所有距离 3、需要用到所有的信息 4、图中不能有负数权重 dijkstra算法过程 今天不是铅笔加手写 python+优先队列实现(这里用的时二叉堆) def showGraph(linkList): for vert in linkList: for n in v...

铁血军的小博客 8317

算法导论 第六章 二叉堆

前言    通常的编程学习中,我们都会接触到堆这种树结构,本篇博客主要讨论最常见的二叉堆,并将其和斐波那契堆与二项堆进行一些比较。 二叉堆的定义     二叉堆顾名思义是形如二叉树的堆,而且是完全二叉树,不过其底层实现通常都是用的数组。因为如果将其从上到下,从左到右依次从1开始编号,正好可以填满数组的前部分,更重要的是实现简单高效,编号此时即为数组索引。如下图即为一个最大堆:

V然成风 1446

深入浅出:用C++实现二叉堆的艺术

在探索数据结构的宏伟宇宙中,二叉堆占据了其独特的一席之地。作为优先队列的基石,它在算法设计和数据处理中扮演着至关重要的角色。本篇博客旨在深入浅出地介绍如何在C++中实现二叉堆,无论你是数据结构的新手还是寻求更深层次理解的开发者,都能从中获得宝贵的知识和技能。

探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。 1953

6.二叉堆实现算法

刚才聊了一会天,思路有点乱了,努力整理了一下!!! 二叉堆其实就是像生成树一样的方式: 其中还是有一些很nice的约束,就拿其中一个三角节点来看,要求父节点的值一定要大于两个子节点的值,然后为了满足这个约束,下面就产生了一些约束生成的伪代码: 算法伪代码: MAX-HEAPIFY(A,I) 1.    l &lt;- LEFT(i) //其中 i,l,r都为上述图片中圆圈外的数组标号...

假先生智铭 336

看动画学算法之:二叉堆Binary Heap

我们坐在高高的谷堆旁边,听妈妈讲那过去的事情。听到了堆,我就想起了这首歌。 没错,今天我们要介绍一个堆,这个堆叫做二叉堆。 二叉树我们之前讲过了,就是每个节点最多有两个子节点的树叫做二叉树。而二叉堆Binary Heap是一种特殊的二叉树。

程序那些事 9114

python二叉堆

定义 二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种:最大堆和最小堆。最大堆:父结点的键值总是大于或等于任何一个子节点的键值; 最小堆:父结点的键值总是小于或等于任何一个子节点的键值。 二叉堆一般用数组来表示。如果根节点在数组中的位置是1,第n个位置的子节点分别在2n和 2n+1。因此,第1个位置的子节点在2和3,第2个位置的子节点在4和5。以此类推。这种基于1的数组存储方式便于寻找父节点和子节点。 二叉堆的根节点叫做堆顶。 最大堆和最小堆的特点

洪源的博客 1万+

数组实现的二叉堆深度解析及应用

最大堆是一种特殊的完全二叉树,其内部结构满足父节点的值总是大于或等于任何一个子节点的值。这意味着树的根节点是所有节点中的最大值,这样的性质使得最大堆成为了一种优先队列的实现方式。最大堆的逻辑结构可以用数组来表示。假设父节点的索引为i,那么其左子节点的索引为2i + 1,右子节点的索引为2i + 2。同样地,对于任一子节点,其父节点的索引可以通过计算(索引 - 1) / 2得到。最大堆的结构特点决定了其在数据结构和算法中的重要性。

weixin_32306683的博客 1026

二叉堆的实现

有图可以看出56和30是70的第一,第二孩子,我们很容易得到他们的下标关系,孩子1的下标是父节点下标的2倍+1,孩子2的下标是父节点下标的2倍+2。大堆中向下调整是和子节点中大的值交换,一开始我们不知道哪个子节点是更大的,所以不妨假设第一个子节点最大,如果假设不成立就让子节点++,变成第二子节点。这里实现的是大堆(根节点最大)的向上调整,swap函数对要调整的两值进行交换,首先我们要知道在二叉堆中子节点和父节点的关系。接下来看看我们实现的大堆的效果,第一行是打印堆的元素,第二是利用堆来排序。

2301_79274600的博客 1388

Proteus一体化安装STC15库添加

Proteus一体化安装与STC15库添加指南 本文详细介绍了Proteus 8.9 SP2专业版的一体化安装流程和STC15系列单片机库文件的添加方法。安装过程简单快捷,无需破解,稳定性好。通过将两个库文件(Lib和LIB)复制到Proteus安装目录的DATA/LIBRARY文件夹中,即可实现STC15W4K32S4芯片的仿真功能。文中还提供了新建工程和器件放置的步骤说明,特别指出STC15W4K32S4芯片可兼容仿真其他STC15系列芯片,并附带下载链接获取资源。该教程适用于电子设计初学者和开发者。

#法外狂徒张三的博客 4万+

Springboot计算机毕业设计校园树洞微信小程序【附源码】开题+论文+mysql+程序+部署

因此,开发一款专门针对校园用户的树洞微信小程序,为学生提供一个安全、私密、便捷的倾诉和交流平台,具有重要的现实意义和应用价值。通过本研究的实施,我们预期能够开发出一款功能全面、操作便捷的校园树洞微信小程序,为校园师生提供一个安全、私密、便捷的倾诉和交流平台。此外,通过不断优化和改进小程序的功能和服务,我们预期能够提升用户体验和满意度,推动校园树洞小程序的持续发展,并为校园生活的和谐与健康发展做出积极贡献。同时,通过不断优化小程序的功能和服务,提升用户体验和满意度,推动校园树洞小程序的广泛应用和持续发展。

光冯毕设程序 1666

二叉堆(c++实现)

二叉堆的介绍 二叉堆是完全二元树或者是近似完全二元树,按照数据的排列方式可以分为两种:最大堆和最小堆。 最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。示意图如下: 二叉堆一般都通过"数组"来实现。数组实现的二叉堆,父节点和子节点的位置存在一定的关系。有时候,我们将"二叉堆的第一个元素"放在数组索引0的位置,有时候放在1的位置。当然,它们的本质一样(都是二叉堆),只是实现上稍微有一点点的区别。 假设"第一个元素"在数组中的索引为 0 的话,则

weixin_41009689的博客 1056

Optisystem软件与Matlab软件的联合数据读取

目录 Matlab软件程序编写 Optisystem软件的连接与设置 数据读取结果 Matlab软件程序编写 利用Matlab软件按照下图编写程序,保存为getdata.m文件。 OutputPort1 =InputPort1; fileID=fopen('OSAdata.txt','wt'); fprintf(fileID,'%f\n',OutputPort1.Sampled.Signal); fclose(fileID); Optisystem软件的连接与设置 (以基于线性插值法

Vivian_Chen_的博客 4853

c++实现二叉堆及堆排序

一、什么是二叉堆

远走的兔子博客 3201

AgentScope Java 2.0 最佳实践:9 个完整示例手把手带你开发 Java‑Agent

本文基于9 个完整示例,深入剖析从基础对话(BasicChatExample)、工具调用(@Tool 注解)、结构化输出(POJO Schema)、ToolGroup 自主管理、MCP 外部工具集成、Hook 生命周期监控、Spring Boot SSE 流式 Web、JsonSession 会话持久化到中断恢复的全链路实战教程。

program哲学 1633

51-14 Retentive Network,RetNet 多尺度保留机制序列建模论文精读

RetNet 提出了多尺度保留机制序列建模,该机制支持三种计算范式,即并行、循环和分块循环。RetNet有更好的全局注意力建模、高效的计算效率、对遮挡的鲁棒性、支持基于注意力的图像生成、与置信度相关的门控机制和多任务学习等特点,对不同视觉任务可以共享历史注意力记忆,可以同时进行分类、分割、检测等任务。RetNet在视觉领域应该有广阔的应用前景。

AIgraphX 1613

a-star算法+二叉堆优化

熬点

nosources的专栏 1464

【Bug已解决】Codex 报错 MCP client for context7 failed to start: program not found 解决方案

方案适用场景推荐指数改用绝对路径Windows 上最常见、最有效的解决方式⭐⭐⭐⭐⭐提前全局安装避免依赖 npx减少运行时网络下载的不确定性⭐⭐⭐⭐使用 .cmd 后缀Windows 平台快速尝试⭐⭐⭐⭐开启调试日志需要更精确定位失败原因⭐⭐⭐⭐统一封装启动脚本需要跨平台兼容多个 MCP 服务⭐⭐⭐报错的本质是Codex 启动 MCP 子进程时,无法正确定位配置文件中写的简写命令名对应的可执行文件,尤其容易发生在 Windows 平台上使用npx这类简写命令的场景。

一键难忘的博客 5814

二叉堆在dijkstra算法中的应用

Dijkstra算法是用于解决加权图中单源最短路径问题的经典算法之一。该算法的核心在于通过逐步选择当前距离起始节点最近的未访问节点来不断更新其他节点的距离值,直到所有目标节点都被访问完毕。在实际实现中,如何高效地维护这些候选节点成为影响Dijkstra算法性能的关键因素。二叉堆(Binary Heap),作为一种特殊的堆数据结构,能够以O(log n)的时间复杂度完成插入、删除和最小元素的检索操作。这一特性使得它成为了Dijkstra算法的理想选择之一,在实际应用中能够显著提升算法的执行效率。

2501_92375421的博客 774

【BIM入门实战】Revit创建地形的几种方法及优缺点

Revit在体量和场地选项卡的【地形表面】工具可以创建三维地形,有三种方法:放置点、指定点文件和导入实例文件、倾斜摄影点云技术和InfraWorks地形生成。 文章目录1. 放置点2. 指定点文件3. 导入实例文件4. 倾斜摄影点云技术5. InfraWorks地形生成 1. 放置点 放置点功能位于体量和场地选项卡下地形表面,点开找到放置点,并通过自定义设置点的高程值来创建地形的高程数据。 优点:通过用户自定义高程点来绘制模型,使地形更为精确。 缺点:只适用于面积小的项目,面积太大,人工效率低下。 .

智慧空间实验室 4759

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

二叉堆的节点插入、删除以及构建过程

目录 什么是二叉堆 二叉堆的基本操作 1.插入节点 2.删除节点 3.构建二叉堆 代码实现 什么是二叉堆 定义:二叉堆,本质上是一种完全二叉树。 分类:二叉堆分为最大堆和最小堆两种类型,最大堆和最小堆分别又可称为大顶堆和小顶堆。最大堆中,任何一个父节点的值都大于或等于它的左、右孩子节点的值;最小堆中,任何一个父节点的值都小于或等于它的左、右孩子节点的值。 二叉堆的根节点叫做...

长林攻城狮的博客 4251

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

二叉堆(最小堆, 最大堆)介绍与实现

二叉堆是一种特殊的二叉树, 它总是保证一棵树的最小元素(最小堆)或者最大元素(最大堆)处于树根上, 常见的应用场景就是用于构建优先队列, 在jdk中Doug Lea所实现的ScheduledThreadPoolExecutor中就是用到了最小堆; 二叉堆介绍 二叉堆的编程实现 应用场景 二叉堆介绍 什么是树? 计算机中树是一种数据结构(有向无环图), 因为它看起来像一颗倒挂的树, 所以被称为树...

江无羡 1万+

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

上一篇: 《算法之美》---二叉搜索树
下一篇: 《ASCE1885的IT笔试面试题》---0000 0001
ACE1985
博客等级 码龄17年 1307粉丝 308原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值