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

6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)

目录

一.堆(Heap)的基本介绍

二.堆的常用操作(以小根堆为例)

三.实现代码

3.1 堆结构定义

3.2 向下调整算法*

3.3 初始化堆*

3.4 销毁堆

3.4 向上调整算法*

 3.5 插入数据

3.6 删除数据

3.7 返回堆顶数据

四.下篇内容

1.堆排序

2.TopK问题


一.堆(Heap)的基本介绍

        了解堆之前我们要简单了解完全二叉树:        

        在二叉树中,我们使用指针来连接每一个结点,最后构成一颗二叉树。而堆是一种使用数组来表示完全二叉树。其满足以下两条规则。

        1.堆中结点值总是大于或者小于其父结点的值。

        2.堆总是一颗完全二叉树。

由此可以推出有两种堆:大根堆和小根堆。

大根堆:根节点的值最大。

小根堆:根节点的值最小。

在堆(二叉树)中,如果一个结点的下标为i

其父亲的结点的下标为 (i-1)/ 2

其左孩子结点的下标为 (i+1)*2 -1  即  i*2 +1

其右孩子结点的下标为 (i+1)*2      即  i*2 + 2

数组的下标由0开始,读者可根据下图进行理解

二.堆的常用操作(以小根堆为例)

//初始化堆
void HeapInit(Heap* php, DataType* arr, int n);//数组建堆主要依赖的算法(这个算法要求数组的左右子树都是小堆)
//小堆,使用向下调整算法
void Adjustdown(DataType* arr, int n, int root);//向上调整算法
void Adjustup(DataType* arr, int n, int root);//销毁堆
void HeapDestory(Heap* php);//插入数据
void HeapPush(Heap* php, DataType x);//删除数据
void HeapPop(Heap* php, DataType x);//求堆顶(根)数据
DataType HeadTop(Heap* php);//交换两个数据
void swap(DataType* p1, DataType* p2);

三.实现代码

3.1 堆结构定义

//以小根堆为例
typedef int DataType;
typedef struct Heap
{DataType* arr;    //数组int capacity;     //容量int size;         //元素大小
}Heap;

3.2 向下调整算法*

        小根堆使用该算法的前提是左右子树都为小根堆,大根堆的前提是左右子树都为大根堆

该算法是从根结点依次向下找到比自己小(或者大)的结点,然后进行交换。

最后就能将新插入的根节点放到相应的位置

调整规则:

小根堆:根节点每一次与孩子结点中较小的一个交换

大根堆:根节点每一次与孩子结点中较大的一个交换

如下图

代码如下(以小根堆为例)

//向下调整算法
void Adjustdown(DataType* arr, int n, int root)
{//1.小根堆,找出左右孩子中较小的结点int parent = root;int child = root * 2 + 1;	//表示左孩子while (child < n){//找到右孩子,如果右孩子比左孩子小,让child++。注意必须存在右孩子才能这么做if (child + 1 < n && arr[child + 1] < arr[child]){child++;}//如果该孩子比父亲小,就要交换if (arr[child] < arr[parent]){swap(arr[child], arr[parent]);//向下继续调整parent = child;child = parent * 2 + 1;}else{//如果孩子比父亲大,交换结束break;}}
}

3.3 初始化堆*

        初始化堆:将一个随机的数组(数组大小随机,元素大小也随机)转换为堆。

思路:

1.将一个数组拷贝到一个堆结构中

2.利用向下调整算法对整个数组进行调整,由于整个数组不能直接进行向下调整(左右子树不符合堆结构),所以我们使用向下调整算法堆 最后一个结点的父亲结点开始调整,然后依次对这个结点之前的结点开始调整。

3.最后得出完整的堆结构

流程图:

代码

//初始化堆
void HeapInit(Heap* hp, DataType* arr, int n)
{//开辟空间,大小为 DataType*nhp->arr = (DataType*)malloc(sizeof(DataType) * n);assert(hp->arr != nullptr);memcpy(hp->arr, arr, sizeof(DataType) * n);hp->size = n;hp->capacity = n;//拷贝好数据后,由于数据是随机的,所以我们使用调整算法建堆//我们从最后一个度为2的结点开始向前依次对每一个结点都进行向下调整//最后一个结点下标为 n-1 则其父亲结点为(n-1-1)/2for (int i = (n - 1 - 1) / 2; i > 0; i--){Adjustdown(hp->arr, hp->size, i);}
}

3.4 销毁堆

//销毁堆
void HeapDestory(Heap* php)
{assert(php);free(php->arr);php->arr = NULL;php->size = 0;php->capacity = 0;
}

3.4 向上调整算法*

当我们插入新数据时,这个数据会破坏堆结构(如插入到数组末尾),所以我们需要向上调整

和向下调整算法类似

思路:

        让新增节点依次和自己的父亲比较,然后交换即可

        小根堆:比父亲小,交换。直到比父亲大就结束

        大根堆:比父亲大,交换。直到比父亲小就结束

流程图:

代码

//向上调整算法,以小根堆为例
void Adjustup(DataType* arr, int n, int child)
{int parent = (child - 1) / 2;while (child > 0){if (arr[child] < arr[parent]){swap(arr[child], arr[parent]);//继续向上调整child = parent;parent = (child - 1) / 2;}else{break;}}
}

 3.5 插入数据

//插入数据
void HeapPush(Heap* hp, DataType x)
{assert(hp);//1.增容if (hp->size == hp->capacity){hp->capacity *= 2;DataType* tmp = (DataType*)realloc(hp->arr, sizeof(DataType) * hp->capacity);assert(tmp != NULL);hp->arr = tmp;}//2.在数组的插入数据hp->arr[hp->size] = x;hp->size++;//对数组进行向上调整,将小的数据向上调整Adjustup(hp->arr, hp->size, hp->size - 1);
}

3.6 删除数据

删除堆顶的数据

我们交换第一个数据和最后一个数据,然后删除最后一个数据。再对堆顶进行向下调整

这样就能满足删除后,整个堆还是满足规则的

//删除数据(删掉堆顶的数据)
//类似于堆排序,交换第一个和最后一个数据。保证根节点的左右子树都是小根堆
void HeapPop(Heap* hp)
{assert(hp);assert(hp->arr);swap(hp->arr[0], hp->arr[hp->size - 1]);hp->size--;Adjustdown(hp->arr, hp->size, 0);
}

3.7 返回堆顶数据

直接返回0下标处的数据即可

//求堆顶(根)数据
DataType HeadTop(Heap* hp)
{assert(hp);assert(hp->size > 0);return hp->arr[0];
}

四.下篇内容

1.堆排序

2.TopK问题

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 8. GIS数据分析师岗位职责、技术要求和常见面试题
  • 深度学习中常见的权重参数初始化方法
  • argodb自定义函数读取hdfs文件的注意点,避免FileSystem已关闭异常
  • C++手记
  • C语言深度剖析--不定期更新的第五弹
  • HCIA--实验十一:单区域OSPF路由实验
  • maven配置文件常用模板
  • 小琳AI课堂:深入学习BERT
  • python 解析数据后保存到excel
  • 零工市场小程序:自由职业者的日常工具
  • 大数据之Flink(六)
  • 活动|华院计算宣晓华受邀出席“AI引领新工业革命”大会,探讨全球科技的最新趋势
  • 一些免费电子书地址总结
  • 基于微信小程序与嵌入式系统的智能小车开发(详细流程)
  • MyBatis 源码解析:XMLScriptBuilder 工作机制
  • 【每日笔记】【Go学习笔记】2019-01-10 codis proxy处理流程
  • 【刷算法】从上往下打印二叉树
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • 08.Android之View事件问题
  • 2017前端实习生面试总结
  • Angular 2 DI - IoC DI - 1
  • Dubbo 整合 Pinpoint 做分布式服务请求跟踪
  • emacs初体验
  • js对象的深浅拷贝
  • node-glob通配符
  • python 学习笔记 - Queue Pipes,进程间通讯
  • session共享问题解决方案
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 机器学习学习笔记一
  • 基于HAProxy的高性能缓存服务器nuster
  • 技术:超级实用的电脑小技巧
  • 阿里云API、SDK和CLI应用实践方案
  • ######## golang各章节终篇索引 ########
  • #if等命令的学习
  • (4)事件处理——(7)简单事件(Simple events)
  • (js)循环条件满足时终止循环
  • (板子)A* astar算法,AcWing第k短路+八数码 带注释
  • (六)Flink 窗口计算
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (四)stm32之通信协议
  • (四)搭建容器云管理平台笔记—安装ETCD(不使用证书)
  • (五十)第 7 章 图(有向图的十字链表存储)
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (自用)仿写程序
  • ***利用Ms05002溢出找“肉鸡
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .NET Framework 服务实现监控可观测性最佳实践
  • .net 设置默认首页
  • .NET/C# 判断某个类是否是泛型类型或泛型接口的子类型
  • .Net实现SCrypt Hash加密
  • [ 2222 ]http://e.eqxiu.com/s/wJMf15Ku
  • [ CTF ] WriteUp-2022年春秋杯网络安全联赛-冬季赛
  • [ vulhub漏洞复现篇 ] JBOSS AS 4.x以下反序列化远程代码执行漏洞CVE-2017-7504
  • [000-01-022].第03节:RabbitMQ环境搭建