【数据结构】堆(Heep)

✨✨✨专栏:数据结构     

          🧑‍🎓个人主页:SWsunlight


目录

一、堆:

定义:

性质:

大、小根堆:

二、实现堆(完全二叉树):

前言:

1、堆的定义:

2、堆的初始化:

 3、销毁:

  4、判空:

5、交换数组中2个数据:

6、 堆的插入:

 7、大、小堆向上调整:

 8、堆的删除:

9、大、小堆向下调整:

10、数据个数和取堆顶数据:

三、代码实现: 

Heap.h头文件:

Heap.c源文件:

test.c源文件:


一、堆:

定义:

        堆(Heap)是计算机科学中一类特殊的数据结构,是最高效的优先级队列。堆通常是一个可以被看作一棵完全二叉树的数组对象。

性质:

1、总是一颗完全二叉树;

2、堆的某个节点的值总是大于等于或者小于等于其父亲节点;

大、小根堆:

要求的就是父子关系 

大根堆:任何一个父亲结点>=孩子结点

孩子与自己爹 谁大谁当爹

小根堆:所有的父亲结点<=孩子结点(倒反天罡)

孩子与自己爹 谁小谁当爹

注意: 不一定是升序;因为只是要求的兄弟节点没有进行大小比较,那么兄弟的孩子可以比兄弟小,但可以比你大

特点:

      》》 根结点是最小(小堆)或者最大值(大堆) (可以用来找极值和排序,效率高)

二、实现堆(完全二叉树):

前言:

需要实现的操作:

  • 堆的定义
  • 堆的初始化
  • 堆的销毁
  • 判空
  • 数据交换
  • 大、小堆向上调整
  • 堆的插入
    • 大堆插入
    • 小堆插入
  • 大、小堆向下调整
  • 删除堆顶元素
    • 大堆删除
    • 小堆删除
  • 查看堆顶数据
  • 数据个数

 因为大小堆有些实现函数是一样的,所以我将接口进行了细分;虽然大小堆插入和删除不同,但就是只是因为向上和向下调整的差别,所以我将上下调整和插入删除分别分装成2个接口,然后将2个接口放到一个专门的函数去调用各自需要的接口完成插入和删除

1、堆的定义:

a是指向数据域的指针(数组),size计数,capacity空间容量;创建方式:和顺序表一样

2、堆的初始化:

写了很多次了的问题:根据结构体成员进行一一初始化即可

 3、销毁:

  4、判空:

看数据个数,若是个数为0,返回true

5、交换数组中2个数据:

在下面的接口实现中,都要用到数组内数组的交换,因为你要满足堆的性质,根据需求保证父子关系

6、 堆的插入:

先判断是否要扩容,然后就是在数组里放数据,插入要根据你的需求来:比如大堆的话,要保证孩子节点比它的父亲节点小,因为它的父亲比它父亲的父亲也要小,所以孩子节点要和它的祖先比较大小。才能完成一次插入,这里的插入并不完整

 7、大、小堆向上调整:

        将数据插到了堆的末尾,因为是根据下标顺序插的,可是我们要满足父子关系(堆的性质),那么必须要让插入的数据和自己的祖先都进行比较。以小堆堆为例:当该结点比若是比自己的祖先都要大就不动它,若是它比自己的祖先大,就要和祖先换个位置“倒反天罡”

看图:一个参数接收数组,一个接收下标;为啥不接收结构体指针,因为我可将这个接口单独拿来进行堆排序;注意判断条件,我们要child>0,不要用parent>=0作为结束条件,因为child=0的时候,parent = -1/2  根据c中整数除法,最后的到结果就是parent = 0;有错误性

用到了公式

大堆的向上:同理的就是将数据比较变成小于变成了大于

 8、堆的删除:

有点特殊,一般我们会想到将其根节点覆盖掉,就如下:我们发现了,结点关系全乱了,我的兄弟变成了我的爹,就是    我拿你当兄弟,你想当我的义父

为了保证堆的性质不变,将最后一个结点和头互换,删除最后一个节点

9、大、小堆向下调整:

继续删除的操作,将堆顶 根据需求进行下调。以小堆为例子:让左孩子和右兄弟进行比较,然后再和父亲比较,谁小谁当爹,直到满足堆的性质

当到最后一层时,有可能没有兄弟,所以一定要控制兄弟

 用假设法,小的就是左孩子,然后就是右孩子的下标要控制在最后一个下标,parent是父亲结点

 大堆类似,就是向下调要改个符号:父亲和2个孩子最大的孩子进行比较,若是比它大。就交换

提示:我们发现了不断删除操作,对于大堆堆顶:可以依次为 最大 次大 …… 最小的数

小堆堆顶:依次为最小,次小……最大的数              

10、数据个数和取堆顶数据:

看一下

三、代码实现: 

Heap.h头文件:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>typedef int HpDataType;
//数组
typedef struct Heap {//数据HpDataType* a;int size;int capacity;
}Hp;//交换数据
void Swp(HpDataType* p1, HpDataType* p2);//初始化:
void HpInit(Hp* phead);//销毁:
void HpDestroy(Hp* phead);//判空:
bool HpEmpty(Hp* phead);//大堆:向上调整
void AdjustUpBig(HpDataType* a,int child);
//大堆:向下调整:n表示的是数据个数,parent表示根节点(老祖宗)
void AdjustDownBig(HpDataType* a, int n,int parent);
//大堆:插入数据
void HpPushBig(Hp* phead, HpDataType x);
//大堆:删出数据
void HpPopBig(Hp* phead);//小堆:向上调整,数组,孩子
void AdjustUpSmall(HpDataType* a, int child);
//小堆:向下调整,数组,孩子
void AdjustDownSmall(HpDataType* a, int n, int parent);
//小堆:插入数据
void HpPushSmall(Hp* phead, HpDataType x);
//小堆:删出数据
void HpPopSmall(Hp* phead);//插入数据
void HpPush(Hp* phead,HpDataType x);
//删除数据:
void HpPop(Hp* phead);
//取数据:
HpDataType Hptop(Hp* phead);
//数据个数:
int Size(Hp* phead);

Heap.c源文件:

//初始化:
void HpInit(Hp* phead)
{//断言:判空!assert(phead);phead->a = NULL;phead->size = phead->capacity = 0;
}//销毁:
void HpDestroy(Hp* phead)
{assert(phead);free(phead->a);phead->a = NULL;phead->size = phead->capacity=0;
}//判空:
bool HpEmpty(Hp* phead)
{assert(phead);//数据个数为0,返回true(真)return phead->size == 0;
}
//大堆:向上调整,child 接受孩子
void AdjustUpBig(HpDataType* a, int child)
{assert(a);int  parent = (child - 1) / 2;//循环的进行从3个方面考虑:// 1、初始条件// 2、中间过程// 3、结束条件//循环有2种写法:while (child>0&&a[child]>a[parent]){		//互换;Swp(&a[child],&a[parent]);child = parent;parent = (child - 1) / 2;}//while (child > 0)//{//	if (a[child] > a[parent])//	{//		//互换;//		Swp(&a[child],&a[parent]);//		child = parent;//		parent = (child - 1) / 2;//	}//	else//	{//		break;//	}//}
}
//大堆:向下调整
void AdjustDownBig(HpDataType* a, int n, int parent)
{assert(a);//用到假设法:我们要保证我的父亲节点比最大的儿子节点大或者相等;假设左孩子大int child = 2 * parent + 1;while (child < n){//判断一下,完全二叉树,有可能会有有孩子不存在的情况if (a[child] < a[child + 1] && child + 1 < n){//??孩子大child = child + 1;}if (a[child] > a[parent]){Swp(&a[child], &a[parent]);parent = child;child = 2 * parent + 1;}else{break;}}}//小堆:向上调整
void AdjustUpSmall(HpDataType* a, int child)
{assert(a);int  parent = (child - 1) / 2;//循环的进行从3个方面考虑:// 1、初始条件// 2、中间过程// 3、结束条件//循环有2种写法:while (child > 0 && a[child] < a[parent]){//互换;Swp(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}}
//小堆:向下调整   n表示数据个数  parent父亲结点,开始时是0(堆顶)
void AdjustDownSmall(HpDataType* a, int n, int parent)
{assert(a);//用到假设法:我们要保证我的父亲节点比最小的儿子节点小或者相等;假设左孩子小int child = 2 * parent + 1;while (child < n){//判断一下,完全二叉树,有可能会有有孩子不存在的情况if (a[child] > a[child + 1] && child + 1 < n){//??孩子小child = child + 1;}//父亲比孩子大,进行交换if (a[child] < a[parent]){Swp(&a[child], &a[parent]);parent = child;child = 2 * parent + 1;}else{break;}}
}//插入数据
void HpPush(Hp* phead, HpDataType x)
{assert(phead);//先扩容://若是没有则先给定义一个:没有则申请4个空间int newcapacity = (phead->capacity == 0 ? 4 : 2 * (phead->capacity));//查看空间够不够:当空间大小与有效数据个数相同时。说明空间不够if (phead->capacity == phead->size){//要先申请空间:申请的内存为 容量*空间大小 HpDataType* pa = (HpDataType*)realloc(phead->a, newcapacity * sizeof(HpDataType));//判断申请是否成功:if (pa == NULL){perror("realloc");return;}//成功了://将空间给arrphead->a = pa;//将改好的空间容量赋值给capacity;phead->capacity = newcapacity;}//开始插入数据phead->a[phead->size++] = x;}//取数据:
HpDataType Hptop(Hp* phead)
{assert(phead);assert(phead->size > 0);return phead->a[0];
}
//数据个数:
int Size(Hp* phead)
{assert(phead);return phead->size;
}//删除栈顶元素,先将栈顶元素和最后一个叶子节点交换
void HpPop(Hp* phead)
{assert(phead);assert(phead->size > 0);//叶子节点和老祖宗换一下,当所有人的祖宗Swp(&phead->a[0],&phead->a[phead->size-1]);phead->size--;
}//交换数据
void Swp(HpDataType* p1, HpDataType* p2)
{assert(p1 && p2);HpDataType tmp = *p2;*p2 = *p1;*p1 = tmp;
}//大堆:插入数据
void HpPushBig(Hp* phead, HpDataType x)
{HpPush(phead, x);//向上进行调整:将最大的放到栈顶(传下标)AdjustUpBig(phead->a, phead->size - 1);}
//大堆:删出数据
void HpPopBig(Hp* phead)
{HpPop(phead);//向下调整 然后进行交换,必须一直保持堆顶元素为最大;AdjustDownBig(phead->a, phead->size, 0);
}//小堆:插入数据
void HpPushSmall(Hp* phead, HpDataType x)
{HpPush(phead, x);AdjustUpSmall(phead->a, phead->size - 1);
}
//小堆:删出数据
void HpPopSmall(Hp* phead)
{HpPop(phead);AdjustDownSmall(phead->a, phead -> size, 0);
}

test.c源文件:

#define _CRT_SECURE_NO_WARNINGS 3
#include"Heap.h"
//大堆:
void Test0()
{int arr[9] = { 1,12,4,5,7,8,9,10 };Hp pts;//初始化:HpInit(&pts);//Pushfor (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){HpPushBig(&pts, arr[i]);}while (!HpEmpty(&pts)){//先取数据,在删除!!printf("%d ", Hptop(&pts));HpPopBig(&pts);}//销毁:HpDestroy(&pts);
}
//小堆:
void Test1()
{int arr[9] = { 1,12,4,5,7,8,9,10 };Hp pts;//初始化:HpInit(&pts);//Pushfor (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){HpPushSmall(&pts, arr[i]);}while (!HpEmpty(&pts)){//先取数据,在删除!!printf("%d ", Hptop(&pts));HpPopSmall(&pts);}//销毁:HpDestroy(&pts);
}
//int main()
{int arr[] = { 1,12,4,5,7,8,9,10 };int n = sizeof(arr) / sizeof(arr[0]);Test0();putchar('\n');Test1();return 0;
}

                      完           结               撒           花

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

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

相关文章

Linux软硬链接及动静态库

软硬链接与动静态库 软连接 创建链接的方法&#xff1a; ln -s test1.txt test2.txt 其中ln 是link(链接)&#xff0c;-s 是soft(软)&#xff0c;后者链接前者。 此时打开test2.txt&#xff0c;发现其中内容与test.txt一致。那么软连接到底建立了什么联系&#xff1f;…

轻松购物,尽在购物网

在忙碌的生活中&#xff0c;想要找到心仪的商品&#xff0c;却总是苦于没有时间和精力去实体店挑选&#xff1f;别担心&#xff0c;购物网为您提供一站式的购物体验。无论是时尚服饰、家居用品&#xff0c;还是美食特产&#xff0c;这里都能满足您的需求。只需轻轻一点&#xf…

C/C++运行时库和UCRT系统通用运行时库总结及问题实例分享

目录 1、概述 2、不同版本的Visual Studio对应的运行时库说明 3、在Windbg10.0安装目录中获取UCRT通用运行时库 4、微软官网对UCRT通用运行时库的相关说明 5、使用Visual Studio 2017开发软件初期遇到的UCRT通用运行时库问题 6、如何查看软件依赖了哪些C/C运行时库&#…

leetcode-盛水最多的容器-109

题目要求 思路 1.正常用双循环外循环i从0开始&#xff0c;内循环从height.size()-1开始去计算每一个值是可以的&#xff0c;但是因为数据量太大&#xff0c;会超时。 2.考虑到超时&#xff0c;需要优化一些&#xff0c;比如第一个选下标1&#xff0c;第二个选下标3和第一个选下…

心识宇宙 x TapData:如何加速落地实时数仓,助力 AI 企业智慧决策

使用 TapData&#xff0c;化繁为简&#xff0c;摆脱手动搭建、维护数据管道的诸多烦扰&#xff0c;轻量代替 OGG、DSG 等同步工具&#xff0c;「CDC 流处理 数据集成」组合拳&#xff0c;加速仓内数据流转&#xff0c;帮助企业将真正具有业务价值的数据作用到实处&#xff0c…

基于springboot实现华府便利店信息管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现华府便利店信息管理系统演示 摘要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本华府便利店信息管理系统就是在这样的大环境下诞生&#xff…

电影《朝云暮雨》观后感

上周看了电影《朝云暮雨》&#xff0c;看完之后&#xff0c;感觉自己整个人都不太好了&#xff0c;也不是说电影太差&#xff0c;只是觉得电影没有传达正能量&#xff0c;让人很不舒服。 &#xff08;1&#xff09;演技在线 对于著名的演员“范伟”&#xff0c;或者说&#x…

Payload SDK dji

开发硬件 感谢您的耐心等待&#xff0c;建议您可以考虑下树莓派4B或Jetson Nano开发板&#xff0c;看您需求选择&#xff0c;OSDK即将停止服务&#xff0c;我们建议您使用PSDK来进行开发&#xff0c;PSDK包含了OSDK的功能。Payload SDK 感谢您对大疆产品的支持&#xff01;祝…

【耕地保卫战:揭秘“占补平衡”】守护粮仓的智慧策略

嗨&#xff0c;各位小伙伴们&#xff0c;今天咱们来聊聊一个与我们每日餐桌紧密相关的主题——耕地占补平衡。在现代化的车轮滚滚向前时&#xff0c;如何在发展与保护之间找到那个微妙的平衡点&#xff0c;确保我们的“米袋子”满满当当呢&#xff1f;这就不得不提到耕地占补平…

论文阅读--Language-driven Semantic Segmentation

效果很好&#xff0c;文本增加一个词&#xff0c;就能找到对应的分割地方&#xff0c;给出的无用标签也不会去错误分割&#xff0c;而且能理解文本意思&#xff0c;例如dog和pet都能把狗给分割出来 image encoder使用DPT分割模型&#xff0c;大致架构为ViTdecoder&#xff0c;d…

【个人经历分享】末流本科地信,毕业转码经验

本人24届末流本科&#xff0c;地理信息科学专业。 我们这个专业可以说是 “高不成&#xff0c;低不就”的专业&#xff0c;什么都学但都不精。考研我实在是卷不动同学历的人&#xff0c;我在大三的时候就开始考虑转码。 至于我为什么选择转码&#xff0c;选择了GIS开发&#xf…

element ui 下拉框Select 选择器 上下箭头旋转方向样式错乱——>优化方案

目录 前言1、问题复现2、预期效果3、input框样式修改解析4、修改方案 &#x1f680;写在最后 前言 测试A&#xff1a;那啥&#xff01;抠图仔&#xff0c;样式怎么点着点着就出问题了。 前端&#xff1a;啥&#xff1f;css样式错乱了&#xff1f;你是不是有缓存啊&#xff01…

linux命令arp的使用

arp arp 命令用于显示和修改 IP 到 MAC 转换表 补充说明 arp 命令 是 Address Resolution Protocol&#xff0c;地址解析协议&#xff0c;是通过解析网络层地址来找寻数据链路层地址的一个网络协议包中极其重要的网络传输协议。而该命令可以显示和修改 arp 协议解析表中的缓…

Mia for Gmail for Mac:Mac用户的邮件管理首选

对于追求高效工作的Mac用户来说&#xff0c;Mia for Gmail for Mac无疑是邮件管理的首选工具。它以其卓越的性能和丰富的功能&#xff0c;为用户带来了前所未有的高效邮件管理体验。 Mia for Gmail for Mac不仅支持多帐号登录和标签选择功能&#xff0c;还提供了邮件分类、垃圾…

linux 中 fd 申请和释放管理(两级 bitmap)

linux 中 fd 的几点理解_linux fd-CSDN博客 通过上边的文章&#xff0c;我们可以知道&#xff0c;在 linux 中&#xff0c;fd 有以下几点需要了解&#xff1a; &#xff08;1&#xff09;fd 表示进程打开的文件&#xff0c;是进程级别的资源&#xff0c;不是系统级别的资源 …

基于manifest文件批量将coding的仓库导入gitlab中

文章目录 写在前面的话背景编写manifest文件最终效果 写在前面的话 前面有讲过通过manifest清单导入项目到gitlab中&#xff0c;但是实际的操作是不同gitlab实例之间的操作&#xff0c;然而对于在不同gitlab实例的repo迁移而言&#xff0c;显然direct transfer会更合适。 背景…

民国漫画杂志《时代漫画》第21期.PDF

时代漫画21.PDF: https://url03.ctfile.com/f/1779803-1248634754-017e2b?p9586 (访问密码: 9586) 《时代漫画》的杂志在1934年诞生了&#xff0c;截止1937年6月战争来临被迫停刊共发行了39期。 ps: 资源来源网络!

结构型模式之桥接模式

文章目录 概述原理结构图代码示例 小结 概述 桥接模式(bridge pattern) 的定义是&#xff1a;将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立地变化。 桥接模式用一种巧妙的方式处理多层继承存在的问题,用抽象关联来取代传统的多层继承,将类之间的静态继承关系转…

基于深度学习OCR文本识别系统源码(带界面)

第一步&#xff1a;概要 基于深度学习OCR文本识别分为两个模块&#xff1a;DBNet和CRNN。 DBNet是基于分割的文本检测算法&#xff0c;算法将可微分二值化模块(Differentiable Binarization)引入了分割模型&#xff0c;使得模型能够通过自适应的阈值图进行二值化&#xff0c;并…

Postgresql 基础学习

一、介绍 PostgreSQL是一个开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它支持SQL语言的所有功能&#xff0c;具有可扩展性、高并发性和可靠性等特点。 以下是一些 PostgreSQL 的特点&#xff1a; 开源&#xff1a;PostgreSQL是一个非常受欢迎的开源…