堆的实现

前言:本文讲述堆实现的几个难点,注意本文主要是以实现为主,建议有些基本概念认识的人阅读。

目录

1.堆

2.堆的实现

堆结构的定义:

要实现的接口:

接口的实现:

堆的初始化和销毁:

向堆中插入数据:

Pop出堆顶的数据

判空,堆的大小 和获得堆顶的值


1.堆

堆的分类:

大堆:

任意父节点都大于等于子节点

小堆:

任意父节点都小于等于子节点

逻辑结构:是满二叉树或完全二叉树

物理结构:数组

一组重要结论通过下标来确定数组中个元素之间的父子关系:这个是重点

leftchild = 2 * parent+1;(左孩子的下标等于父节点下标乘2加1)

rightchild = 2* parent +2;(右孩子的下标等于父节点下标乘2加2)

parent = (child-1)/2;(父亲节点的下标等于任意孩子节点的下标减1除2)

2.堆的实现

这里实现的是小堆

堆结构的定义:

typedef int HeapDataType;
typedef struct Heap
{
	HeapDataType* a;
	int size;
	int capacity;
}Heap;

 因为物理结构是数组,所以要考虑扩容的问题

要实现的接口:

//初始化
void HeapInit(Heap* php);
//销毁
void HeapDestroy(Heap* php);
//插入数据
void HeapPush(Heap* php,HeapDataType x);
//将堆顶的数据pop出
void HeapPop(Heap* php);
//判断堆是否为空
bool HeapEmpty(Heap* php);
//堆中元素的个数
int HeapSize(Heap* php);
//返回堆顶的数据
HeapDataType HeapTop(Heap* php);

接口的实现:

堆的初始化和销毁:

void HeapInit(Heap* php)
{
	assert(php);
	php->a = NULL;
	php->size = 0;
	php->capacity = 0;
}
void HeapDestroy(Heap* php)
{
	assert(php);
	free(php->a);
	php->size = 0;
	php->capacity = 0;
}

向堆中插入数据:

//交换数据
void Swap(HeapDataType* p1, HeapDataType* p2)
{
	HeapDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
//向上调整算法
void AdjustUp(HeapDataType* a, int child)
{
	int parent = (child - 1) >> 1;
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) >> 1;
		}
		else
		{
			break;
		}
	}
}
//向堆中插入数据
void HeapPush(Heap* php,HeapDataType x)
{
	assert(php);
	if (php->size == php->capacity)
	{
		int newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity;
		HeapDataType* tmp = (HeapDataType*)realloc(php->a,sizeof(HeapDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		php->a = tmp;
		php->capacity = newcapacity;
	}
	php->a[php->size++] = x;
	AdjustUp(php->a, php->size - 1);
}

向堆中插入数据的步骤:

1.先考虑是否扩容

2.将需要插入的数据先插入数组下标为size的位置,之后在++

3.插入后需要根据自己的需求来实现向上调整算法

这里的难点是如何实现向上调整算法

通过父节点与子节点的大小比较(正是这个比较的条件决定了建的是大堆还是小堆)来确定父节点与子节点的数据是否发生调换。本文实现的是小堆。你将文章中子节点与父节点的大小比较的比较符号调换一下位置就变成了大堆

还有一点就是向上调整算法的参数为什么要是数组元素的首地址,原因是为了实现后面的堆排序。

Pop出堆顶的数据

注意pop出的数据是数组下标为0的数据,而不是数组最后面的数据

这里建的是小堆

//向下调整算法
void AdjustDown(HeapDataType* a, int size, int parent)
{
	int child = 2 * parent + 1;
    //最坏,左孩子>=size时循环结束,此时的parent是叶节点
	while (child<size)
	{
        //下面的两个条件不能调换位置,不能调换的原因是防止child+1>=size造成非法访问       
		if (child+1<size&&a[child + 1] < a[child])
			child++;
		if (a[child]<a[parent])
		{
			Swap(&a[parent], &a[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}


void HeapPop(Heap* php)
{
	assert(php);
	assert(php->size > 0);
	int end = php->size - 1;
	Swap(&php->a[0], &php->a[end]);
	php->size--;
	AdjustDown(php->a, php->size, 0);
}

步骤:

1.现将堆顶的数据和最后的数据交换,然后再将size--

2.最后对刚换上去的堆顶的数据,采用向下调整算法

为什么pop出堆顶的数据,不直接将数组的数据整体前移一个单位?

答:如果这样做的话,那么堆之间的关系就乱了,需要重新建堆,效率低

那么接下来的难点就是如何实现向下调整算法

代码解释:

图解:

判空,堆的大小 和获得堆顶的值

bool HeapEmpty(Heap* php)
{
	assert(php);
	return php->size == 0;
}
int HeapSize(Heap* php)
{
	assert(php);
	return php->size;
}
HeapDataType HeapTop(Heap* php)
{
	assert(php);
	return php->a[0];
}

这里比较简单就不多讲了。

结语:下一篇的博客将讲讲堆排序的详细内容

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【简单介绍下链表基础知识】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

第八届能源、环境与材料科学国际学术会议(EEMS 2024)

文章目录 一、重要信息二、大会简介三、委员会四、征稿主题五、论文出版六、会议议程七、出版信息八、征稿编辑 一、重要信息 会议官网&#xff1a;http://ic-eems.com主办方&#xff1a;常州大学大会时间&#xff1a;2024年06月7-9日大会地点&#xff1a;新加坡 Holiday Inn …

OA界面这么香吗?总有老铁私信,让我多发点,他好参考。

OA的确是B端系统应用最为广泛的一种&#xff0c;这次再给大家分享十来个页面&#xff0c;希望对他们的界面提升有所帮助。 举报 评论 3

计算机考研|408开始的晚,怎么入手复习?六个月保姆级规划

万事开头难&#xff0c;特别是408 大家在第一遍复习408的时候&#xff0c;基本上都有这个问题&#xff0c;就是复习速度慢&#xff0c;理解成本高&#xff0c;因为数据结构&#xff0c;计算机组成原理这些都是大一大二开始学的内容&#xff0c;等到自己准备考研的时候&#xf…

洗地机哪个牌子最好用?2024洗地机排行榜

随着人们生活水平的提升&#xff0c;智能清洁家电已经成为日常生活中的必需品。如今的清洁家电市场上&#xff0c;洗地机、吸尘器和扫地机器人等设备各有其独特的功能和优势。洗地机结合了扫、拖、吸和自清洁等多种功能&#xff0c;不仅可以处理干湿垃圾&#xff0c;还能高效清…

打破传统相亲模式,这几款靠谱的相亲软件助你脱单

相亲软件在当今社会已经变得越来越普遍&#xff0c;市面上有众多相亲软件可供选择&#xff0c;但哪些相亲软件好用呢&#xff1f;下面介绍几款备受好评的相亲软件&#xff0c;帮助你在茫茫人海中找到那个对的人&#xff01; 1、一伴婚恋 这个APP它最大的优点就是信息真实靠谱…

mac上简单实现一个java调用C接口的JNI

目录 安装JDK及配置环境变量写Java代码生成头文件实现本地方法编译本地代码运行 Java 程序总结步骤 安装JDK及配置环境变量 参考&#xff1a;MAC系统安装JDK1.8及环境变量配置 写Java代码 // 文件名&#xff1a;Calculator.java public class Calculator {// 声明本地方法pu…

Vue 3指令与事件处理

title: Vue 3指令与事件处理 date: 2024/5/25 18:53:37 updated: 2024/5/25 18:53:37 categories: 前端开发 tags: Vue3基础指令详解事件处理高级事件实战案例最佳实践性能优化 第1章 Vue 3基础 1.1 Vue 3简介 Vue 3 是一个由尤雨溪&#xff08;尤大&#xff09;领导的开源…

5.22-wjn

使用select实现的TCP并发服务器端 #define SER_PORT 8888 #define SER_IP "192.168.125.158" int main(int argc, const char *argv[]) {//1、为通信创建一个端点int sfd socket(AF_INET, SOCK_STREAM, 0);//参数1&#xff1a;说明使用的是ipv4通信域//参数2&#…

SpringBoot Bean

配置优先级 Bean的管理 从IOC容器中获取Bean对象&#xff1a;注入IOC容器对象 bean的作用域 Bean对象默认在容器启动时实例化 Lazy在第一次使用时初始化 Bean的管理&#xff1a;第三方Bean 引入依赖&#xff0c;每次解析创建新对象&#xff0c;浪费资源 将第三方对象交给…

vr商品全景展示场景编辑软件的优点

3D模型展示网站搭建编辑器以强大的3D编辑引擎和逼真的渲染效果&#xff0c;让您轻松实现模型展示的优化。让用户通过简单的操作&#xff0c;就能满足个人/设计师/商户多样化展示的需求&#xff0c;让您的模型成为独一无二的杰作。 3D模型展示网站搭建编辑器采用国内领先的实时互…

软件设计师中级

计算机系统 运算器和控制器 算术逻辑单元 累加寄存器器 状态寄存器 数据缓冲寄存器 指令寄存器 程序计数器 地址寄存器 指令译码器 内存按字节编址 内存存储单元16位 1 浮点数 浮点数范围&#xff1a;-2的(2的阶码次)-1到-2的(2的阶码次)-1 乘 1-2负尾数次 海明码 海明码&…

力扣HOT100 - 136. 只出现一次的数字

解题思路&#xff1a; class Solution {public int singleNumber(int[] nums) {int single 0;for (int num : nums) {single ^ num;}return single;} }

Java基础的语法---StringBuilder

StringBuilder 构造方法 StringBuilder()&#xff1a;创建一个空的StringBuilder实例。 StringBuilder(String str)&#xff1a;创建一个StringBuilder实例&#xff0c;并将其初始化为指定的字符串内容。 StringBuilder(int a): 创建一个StringBuilder实例…

AWTK实现汽车仪表Cluster/DashBoard嵌入式GUI开发(七):快启

前言: 汽车仪表是人们了解汽车状况的窗口,而仪表中的大部分信息都是以指示灯形式显示给驾驶者。仪表指示灯图案都较为抽象,对驾驶不熟悉的人在理解仪表指示灯含义方面存在不同程度的困难,尤其对于驾驶新手,如果对指示灯的含义不求甚解,有可能影响驾驶的安全性。即使是对…

Leetcode刷题笔记3:链表基础1

导语 leetcode刷题笔记记录&#xff0c;本篇博客记录链表基础1部分的题目&#xff0c;主要题目包括&#xff1a; 203.移除链表元素707.设计链表206.反转链表 知识点 链表 链表是一种通过指针串联在一起的线性结构&#xff0c;每一个节点由两部分组成&#xff0c;一个是数据…

企业如何防止数据泄密?大型企业必备的文件加密软件

随着信息化建设的大步推进&#xff0c;越来越多的企业资料以电子文件的形式保存&#xff0c;企业内部和企业之间的信息交流也主要依靠电子文件。近年来的泄密事件层出不穷&#xff0c;比如东软泄密案、HTC窃密案、力拓案等&#xff0c;给企业带来灾难性的经济损失及信誉重创。如…

CentOS7安装内网穿透实现远程推送镜像到本地Docker Registry

文章目录 前言1. 部署Docker Registry2. 本地测试推送镜像3. Linux 安装cpolar4. 配置Docker Registry公网访问地址5. 公网远程推送Docker Registry6. 固定Docker Registry公网地址 前言 本文主要介绍如何部署Docker Registry 本地镜像仓库,简单几步结合cpolar内网穿透工具实现…

使用控制台方式部署sentinel

1.下载控制台jar包 2.运行jar包 java -jar sentinel-dashboard-1.8.0.jar 也可以通过编写批处理文件指定端口、用户名、密码&#xff1a; 客户端添加依赖&#xff08;后续整合springcloudalibaba时不需要此依赖&#xff09; 如修改了sentinel端口&#xff0c;需要添加客户端运…

ubuntu下载离线软件包及依赖

目录 一、前言 二、正文 1.准备环境 2.开始下载 3.后续工作 三、总结 一、前言 由于给客户提供的设备机不允许上网&#xff0c;那么所有待安装的软件包及依赖库都需要提前下载好&#xff0c;然后通过局域网传过去再安装。 另外&#xff0c;软件包可能还依赖其他的库&…