二叉树——堆

二叉树顺序存储结构

  理解堆之前先理解一下二叉树的顺序存储结构。普通的二叉树并不适合顺序存储,因为可能会造成大量的空间浪费。只有完全二叉树适合顺序结构存储。显示中我们通常把堆使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统中虚拟进程地中空间中的堆是两回事,这个堆是一个数据结构,而虚拟进程地址空间中的堆是操作系统中管理内存的一块区域分段。
在这里插入图片描述
在这里插入图片描述

堆的概念

  如果有一个关键码集合K={k0,k1,……kn-1},把所有的元素按完全二叉树的吮吸存储方式存储在一个一维数组,并满足:ki<=k2i+1并且ki<=k2i+2,就程这个二叉树为小堆(大堆)。根节点是最大值的堆称为大堆,根节点为最小值称为小堆。

堆的性质

  1. 队中每个结点的值总是不大于或者不小于其父节点
  2. 堆总是一个完全二叉树
  3. 堆中第N个节点的左孩子为第N2+1个节点,右孩子为第N2+2个节点
    在这里插入图片描述

堆的实现

创建堆

在这里插入图片描述
  这个数组从逻辑上可以看作是一个完全二叉树,但他还不是一个堆,需要我们运用向下调整算法将他构成一个堆。对于二叉树来说,如果根节点的左右子树都满足堆,那么这个二叉树就满足堆,所以我们从倒数第二个尾叶子节点开始调整,一直调整到到整个二叉树的根节点为止。

向下调整算法(小堆)

  向下调整算法就是从当前节点开始,依次向下调整,直到不满足条件为止:

  1. 找出当前节点的两个孩子中的最小的孩子(先找左孩子,根据完全二叉树的性质可以直到左孩子存在,右孩子不一定存在)
  2. 如果当前节点比最小的孩子大,就需要与这个孩子交换位置,然后继续向下调整
  3. 如果当前节点比最小的孩子小,就可以结束调整,说明以当前节点为根的二叉树是小堆。
    在这里插入图片描述
    向下调整代码
void AdjustDown(HPData* array, int size, int root, PCOM compare)
{int child = root * 2 + 1;while (child < size){//找左右孩子中最小的孩子if (child + 1 < size && compare(array[child],array[child - 1]))child += 1;if (compare(array[child], array[root])){swap(array[root], array[child]);root = child;child = root * 2 + 1;}elsereturn;}
}
堆插入

  堆创建好了,接下来就是向堆中插元素,只需要将元素放在堆底,然后向上调整
  向上调整就是用当前节点与父节点比较,如果比父结点小,就要交换,然后继续向上调整,如果比父结点大,就结束调整
在这里插入图片描述

堆删除

  堆删除时将对顶元素删除,先将堆顶元素和最后一个元素交换位置,将最后一个元素删除即可,最后从堆顶向下调整。在这里插入图片描述

堆代码的实现


int less(HPData left, HPData right)
{return left < right;
}
int greater(HPData left, HPData right)
{return left > right;
}
//定义函数指针来改变大堆和小堆
typedef int(*PCOM)(HPData left, HPData right);
int less(HPData left, HPData right);
int greater(HPData left, HPData right);//堆结构体
typedef struct Heap
{HPData* _array;int _size;int _capacity;PCOM _compare;
}Heap;//向下调整
void AdjustDown(HPData* array, int size, int root, PCOM compare)
{int child = root * 2 + 1;while (child < size){//找左右孩子中最小的孩子if (child + 1 < size && compare(array[child],array[child - 1]))child += 1;if (compare(array[child], array[root])){swap(array[root], array[child]);root = child;child = root * 2 + 1;}elsereturn;}
}//向上调整
void AdjustUp(HPData* array, int size, int child, PCOM compare)
{int root = (child - 1) >> 1;while (child){if (compare(array[child], array[root])){swap(array[root], array[child]);child = root;root = (child - 1) >> 1;}elsereturn;}
}//堆扩容
void CheckCapacity(Heap* hp)
{assert(hp);int newcapacity = hp->_size * 2;HPData* array = (HPData*)malloc(sizeof(HPData) * newcapacity);if (array == NULL){assert(0);return;}for (int i = 0; i < hp->_size; ++i)array[i] = hp->_array[i];hp->_capacity = newcapacity;free(hp->_array);hp->_array = array;
}//初始化堆
void InitHeap(Heap* hp, HPData* array, int size, PCOM compare)
{assert(hp);hp->_array = (HPData*)malloc(sizeof(HPData)*size);if (NULL == hp->_array){assert(0);return;}hp->_capacity = size;hp->_size = size;hp->_compare = compare;for (int i = 0; i < size; ++i)hp->_array[i] = array[i];int root = ((size - 2) >> 1);for ( ;root >= 0; --root)AdjustDown(hp->_array, size, root, compare);
}//堆插入
void InsertHeap(Heap* hp, HPData data, PCOM compare)
{if (hp->_size == hp->_capacity)CheckCapacity(hp);hp->_array[hp->_size] = data;AdjustUp(hp->_array, hp->_size, hp->_size - 1, compare);}//堆中元素个数
int HeapSize(Heap* hp)
{assert(hp);return hp->_size;
}//堆顶元素
HPData HeapTop(Heap* hp)
{assert(hp);return hp->_array[0];
}//判断是否是空堆
bool HeapEmpty(Heap* hp)
{assert(hp);return hp->_size == 0;
}//删除堆元素
void EraseHeap(Heap* hp)
{if (HeapEmpty(hp))return;swap(hp->_array[0], hp->_array[hp->_size - 1]);hp->_size -= 1;AdjustDown(hp->_array, hp->_size, 0, hp->_compare);
}//销毁堆
void DostroyHeap(Heap* hp)
{assert(hp);if (hp->_array){free(hp->_array);hp->_capacity = 0;hp->_size = 0;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/494838.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

hive函数大全:11大类、109个函数

磨刀不误砍柴工&#xff0c;学完函数再sql 目录 一、关系运算 1. 等值比较: 2. 不等值比较: <> 3.小于比较: < 4. 小于等于比较: < 5. 大于比较: > 6. 大于等于比较: > 7. 空值判断: IS NULL 8. 非空判断: IS NOTNULL 9. LIKE比较: LIKE 10. J…

open AI 在DOTA 5v5 比赛中战胜职业选手

来源&#xff1a;AI科技大本营摘要&#xff1a;去年&#xff0c;OpenAI 在 DOTA 的 1v1 比赛中战胜了职业玩家 Dendi&#xff0c;而在距离进阶版 OpenAI Five 系统战胜人类业余玩家不过一个月的时间&#xff0c;今天凌晨&#xff0c;它又以 2:1 的战绩再次完成对人类高级玩家的…

C/C++程序从源代码到可执行程序的流程

对于一个C/C编写的程序&#xff0c;从源代码到可执行程序的过程通常是由IDE来完成的&#xff0c;一般分为四个步骤&#xff1a;预处理、编译、汇编、链接&#xff0c;下面就来详细说一下这四个步骤。 预处理&#xff1a; 主要是对其中的伪指令和特殊符号进行处理&#xff1a; …

Python 两种装饰器

目录 带参数的装饰器&#xff08;函数&#xff09; 类装饰器 装饰器(Decorators)是 Python 的一个重要部分。简单地说&#xff1a;他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短&#xff0c;也更Pythonic&#xff08;Python范儿&#xff09;。 带参数的装…

如何体现机器智能和群体智能的关系,2018新版互联网大脑模型绘制

作者&#xff1a;刘锋 计算机博士 互联网进化论作者2018年新的这一版&#xff0c;也是互联网大脑模型图的第五个版本&#xff0c;距离第一版的发布已经有10年时间&#xff08;2008年&#xff09;&#xff0c;距离上一版第四版也有1年时间&#xff0c;在这一版中主要解决了如何…

Python可变传参: *args和**kwargs

args是参数的数组&#xff0c;kwargs就是当你传入keyvalue是存储的字典。 请看例子&#xff1a; def test(a,*args,**kwargs): print "a: ",a print "args: ",args print "kwargs: ",kwargs test(1,2,3,d4,e5) 输出结果&#xff1a; a: 1 args: …

7/7 第7篇 函数名与函数指针

第7篇 函数名与函数指针 一 通常的函数调用 一个通常的函数调用的例子&#xff1a; //自行包含头文件 void MyFun(int x); //此处的申明也可写成&#xff1a;void MyFun( int ); int main(int argc, char* argv[]) { MyFun(10); //这里是调用MyFun(10);函数 return 0; }…

全球互联正在创造一个知识极大丰富和隐私终结的时代

来源&#xff1a;资本实验室摘要&#xff1a;据预测&#xff0c;到2020年&#xff0c;全球物联网连接设备将超过500亿个&#xff0c;会产生600泽字节的信息。这么庞大的数据量&#xff0c;将如何影响并改变我们的生活和工作&#xff1f;聚焦前沿科技创新与传统产业升级据预测&a…

大数据计算引擎:impala对比hive

目录 Impala与Hive的异同 数据存储 元数据 SQL解释处理 执行计划&#xff1a; 数据流&#xff1a; 内存使用&#xff1a; 调度&#xff1a; 容错&#xff1a; 适用面&#xff1a; Impala相对于Hive所使用的优化技术 Impala的优缺点 Impala与Hive的异同 数据存储 …

从外部调用Django模块

import os import sys sys.path.insert(0,/data/cloud_manage) from django.core.management import setup_environ import settings setup_environ(settings)from common.monitor import Monitor from django.db import connection, transaction 前提就是&#xff0c;要新建一…

泡沫破裂之后,强化学习路在何方?

作者&#xff5c;侯宇清、陈玉荣来源&#xff5c;智能单元编辑&#xff5c;Debra一、深度强化学习的泡沫2015 年&#xff0c;DeepMind 的 Volodymyr Mnih 等研究员在《自然》杂志上发表论文 Human-level control through deep reinforcement learning[1]&#xff0c;该论文提出…

常见的设计模式--单例模式

设计模式 设计模式&#xff08;Design Pattern&#xff09;是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。使用设计模式的目的是为了代码可重用性、让代码更容易被他人理去解、保证代码可靠性。 设计模式使代码编写真正工程化&#xff1b;设计模式是软件工…

一篇文章搞懂数据仓库:维度表(设计原则、设计方法)

目录 1、什么是维度表&#xff1f; 2、维度表设计原则 &#xff08;1&#xff09;维度属性尽量丰富&#xff0c;为数据使用打下基础 &#xff08;2&#xff09;给出详实的、富有意义的文字描述 &#xff08;3&#xff09;区分数值型属性和事实 &#xff08;4&#xff09;…

javascript 键值转换

for (var i 0; i < headerFields.length; i) {fieldToIndex[headerFields[i]] i;} 转载于:https://www.cnblogs.com/EasonSun/archive/2012/08/03/2621661.html

Github项目:AI消除马赛克实战

目录 1、原理 2、准备工作 3、消除马赛克 4、效果对比 1、原理 该算法利用线性盒滤波器分别处理每个块的事实。对于每个块&#xff0c;它将搜索图像中的所有块像素化以检查直接匹配。 对于大多数像素化图像&#xff0c;Depix能够找到单个匹配结果。它假设这些是正确的。然…

C++继承一览

继承的概念及定义 继承机制是面向对象程序设计是代码可以复用的重要手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生的类称为派生类。继承呈现了面向对象程序设计的层次结构&#xff0c;体现了由简单到复杂的认知过程。…

人工智能能否复制人脑引争论 美媒:目前AI仍存在局限性

来源&#xff1a;网易智能摘要&#xff1a;人们应用人工智能技术&#xff08;AI&#xff09;的所有领域&#xff0c;包括无人驾驶汽车、机器人医生、超过10亿中国公民的社会信用评分系统等&#xff0c;当前都取决于一场关于如何让AI做其不能做的事的辩论。8月6日报道称&#xf…

Tushare免费获取股票数据:实时数据,历史数据,行情数据

一 操作手册 引导用户顺利开始使用Tushare Pro数据&#xff0c;以下步骤将带您开始Tushare数据之旅&#xff1a; 用户注册登录后可调用数据&#xff1a;https://tushare.pro/register?reg399205 二 如何获取TOKEN凭证 1、登录成功后&#xff0c;点击右上角->个人主页 2、…

2012/8/3 Extjs使用TabPanel时需要注意的问题

在创建Ext.TabPanel时&#xff0c;配置项deferredRender经常会被忽略&#xff0c;关于这个配置项&#xff0c;我们来看一下API文档的解释&#xff1a;“内置地&#xff0c;Tab面板是采用Ext.layout.CardLayout的方法管理tabs。此属性的值将会传递到布局的Ext.layout.CardLayout…

排序(冒泡、选择、插入、希尔、快排、堆排、归并)

冒泡排序 冒泡排序时通过无序区中相邻记录的关键字间的比较和位置的交换&#xff0c;使关键字最小的元素如气泡似的逐步上浮直水面。有序区逐渐扩大&#xff0c;无序区逐渐缩小。   冒泡排序算法的原理如下&#xff1a; 比较相邻的元素。如果第一个比第二个大&#xff0c;就…