数据结构入门(C语言版)二叉树的顺序结构及堆的概念及结构实现应用

news2025/1/21 5:51:14

在这里插入图片描述

二叉树的顺序结构及堆的概念及结构实现

  • 二叉树的顺序结构
  • 堆的概念及结构
  • 堆的实现
    • 1、堆向下调整算法
    • 2、堆的创建
    • 3、堆的插入
    • 4、堆的实现
      • 向上调整(AdjustUp)
      • 向下调整(AdjustDown)
      • 堆的初始化(HeapInit)
      • 堆的销毁(HeapDestroy)
      • 堆的插入(HeapPush)
      • 堆的删除(HeapPop)
      • 取堆顶的数据(HeapTop)
      • 堆的打印(HeapPrint)
      • 堆的判空(HeapEmpty)
      • 堆的数据个数(HeapSize)
  • 堆排序的简易例子
  • 结语

二叉树的顺序结构

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段

堆的概念及结构

在这里我们先学习一下堆,堆是一种特殊的二叉树形式
如果有一个关键码的集合K = { N1,N2 ,N3 ,…, },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足: Ni<= N(2i+1)且 Ni<= N(2i+2)( Ni>= N(2i+1)且Ni >=N(2i+2) ) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的性质:
★堆中某个节点的值总是不大于或不小于其父节点的值;
★堆总是一棵完全二叉树。
在这里插入图片描述
在这里插入图片描述

堆的实现

1、堆向下调整算法

现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

int arr[] = {27,15,19,18,28,34,65,49,25,37};

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
后面在讲到堆的插入接口函数时,还会提到向上调整算法

2、堆的创建

下面我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。根节点左右子树不是堆,我们怎么调整呢?这里我们从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成堆。

int a[] = {1,5,3,8,7,6};

在这里插入图片描述
请添加图片描述
在这里插入图片描述
在这里插入图片描述
此时调换1和8的位置时,8的左子树堆结构被破坏,所以在每一次发生元素交换的时候,都需要递归调用重新构造堆的结构
在这里插入图片描述
在这里插入图片描述
最后构造的大堆:8,7,6,5,1,3

3、堆的插入

删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
★将堆顶元素和堆中最后一个元素进行交换
★删除最后一个元素
★将堆顶的元素向下调整,直到满足堆特性为止

4、堆的实现

这里堆的实现我们使用的是顺序表结构
堆的结构体及接口定义

// 大堆
typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}HP;

void AdjustUp(int* a, int child);//向上调整
void AdjustDown(int* a, int n, int parent);//向下调整

void Swap(HPDataType* px, HPDataType* py);//交换函数
void HeapInit(HP* hp);//堆的初始化
void HeapDestroy(HP* hp);// 堆的销毁
void HeapPush(HP* hp, HPDataType x);// 堆的插入
void HeapPop(HP* hp);// 堆的删除
HPDataType HeapTop(HP* hp);// 取堆顶的数据
void HeapPrint(HP* hp);//堆的打印
bool HeapEmpty(HP* hp);// 堆的判空
int HeapSize(HP* hp);// 堆的数据个数

堆的接口实现

交换函数(Swap)
代码如下:

void Swap(HPDataType* px, HPDataType* py)
{
	HPDataType tmp = *px;
	*px = *py;
	*py = tmp;
}

这里的交换函数不是接口函数,仅为了方便其他接口函数调用

向上调整(AdjustUp)

代码如下:

void AdjustUp(int* a, int child)
{
	assert(a);

	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);

			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

这里的向上调整函数就是指定一个元素与其父亲比较,如果孩子小于父亲,就交换
常用于小堆的插入与堆排序。

向下调整(AdjustDown)

代码如下:

void AdjustDown(int* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		// 选出左右孩子中小的那一个
		if (child + 1 < n && a[child + 1] < a[child])
		{
			++child;
		}

		// 如果小的孩子小于父亲,则交换,并继续向下调整
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

这里的向下调整函数就是指定一个元素与其父亲比较,如果孩子小于父亲,就交换
同样常用于小堆的插入与堆排序,和向上调整的不同的就是方向。

堆的初始化(HeapInit)

代码如下:

void HeapInit(HP* hp)
{
	assert(hp);
	hp->a = NULL;
	hp->size = hp->capacity = 0;
}

堆的销毁(HeapDestroy)

代码如下:

void HeapDestroy(HP* hp)
{
	assert(hp);
	free(hp->a);
	hp->capacity = hp->size = 0;
}

堆的插入(HeapPush)

代码如下:

void HeapPush(HP* hp, HPDataType x)
{
	assert(hp);
	if (hp->size == hp->capacity)
	{
		size_t newCapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;
		HPDataType* tmp = realloc(hp->a, sizeof(HPDataType)*newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}

		hp->a = tmp;
		hp->capacity = newCapacity;
	}

	hp->a[hp->size] = x;
	hp->size++;
	AdjustUp(hp->a, hp->size - 1);
}

堆的插入,首先创建内存空间,然后插入元素,size++就不说了;
重点讲一下这里的向上调整,因为是小数往上调,所以这里的调用是用于小堆的建立;
如果要改成大堆,那么就要将向上调整函数的判断改为大于;
修改后代码如下:

if (a[child] >  a[parent])

堆的删除(HeapPop)

代码如下:

void HeapPop(HP* hp)
{
	assert(hp);
	assert(!HeapEmpty(hp));

	Swap(&hp->a[0], &hp->a[hp->size - 1]);
	hp->size--;

	AdjustDown(hp->a, hp->size, 0);
}

堆的删除是删除堆顶的元素,但是需要注意的是并不是直接将堆顶元素直接删除
而是将堆顶元素和最后一个元素交换,再进行size–
再将换上去的最后的元素重新向下调整到相应位置
这样做的目的是为了保持堆的基本结构,否则可能堆结构可能不成立。

取堆顶的数据(HeapTop)

代码如下:

HPDataType HeapTop(HP* hp)
{
	assert(hp);
	assert(!HeapEmpty(hp));

	return hp->a[0];
}

直接返回第一个元素即可

堆的打印(HeapPrint)

代码如下:

void HeapPrint(HP* hp)
{
	for (int i = 0; i < hp->size; ++i)
	{
		printf("%d ", hp->a[i]);
	}
	printf("\n");
}

常用的for循环对顺序表进行元素遍历逐个打印

堆的判空(HeapEmpty)

代码如下:

bool HeapEmpty(HP* hp)
{
	assert(hp);

	return hp->size == 0;
}

这里使用的是bool值,当然你也可以使用int类型

堆的数据个数(HeapSize)

代码如下:

int HeapSize(HP* hp)
{
	assert(hp);
	return hp->size;
}

堆排序的简易例子

代码如下:

void HeapSort(int* a, int n)
{
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	}
	for (int end = n - 1; end > 0; --end)
	{
		Swap(&a[end], &a[0]);
		AdjustDown(a, end, 0);
	}
}
int main()
{
	int a[] = { 70, 56, 30, 25, 15, 10, 75, 33, 50, 69 };
	HeapSort(a, sizeof(a) / sizeof(a[0]));
	for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
	{
		printf("%d ", a[i]);
	}
	printf("\n");

	return 0;
}

这里我们主要使用向下调整的方法来实现,因为上面对堆的删除是用于小堆
所以这里调用向下调整后,该数组为降序,排序后打印如下:

75 70 69 56 50 33 30 25 15 10

如果要进行升序排序,我们只需将向下调整函数的部分符号修改即可
修改如下:

void AdjustDown(int* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] > a[child])
		{
			++child;
		}
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

排序后打印如下:

10 15 25 30 33 50 56 69 70 75

结语

有兴趣的小伙伴可以关注作者,如果觉得内容不错,请给个一键三连吧,蟹蟹你哟!!!
制作不易,如有不正之处敬请指出
感谢大家的来访,UU们的观看是我坚持下去的动力
在时间的催化剂下,让我们彼此都成为更优秀的人吧!!!
在这里插入图片描述

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

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

相关文章

【微服务笔记14】微服务组件之Config配置中心高可用环境搭建

这篇文章&#xff0c;主要介绍微服务组件之Config配置中心高可用环境搭建。 目录 一、高可用Config配置中心 1.1、高可用配置中心介绍 1.2、搭建Eureka注册中心 1.3、搭建ConfigServer服务端 &#xff08;1&#xff09;引入依赖 &#xff08;2&#xff09;添加配置文件 …

北上广测试工程师月薪20K往上,该如何做,需要会什么技能?

有人回答说这只能是大企业或者互联网企业工程师才能拿到。也许是的&#xff0c;小公司或者非互联网企业拿两万的不太可能是码农了&#xff0c;应该已经转管理。还有区域问题&#xff0c;这个不在我的考虑范围内&#xff0c;因为除了北上广深杭&#xff0c;其他地方也很难达到。…

代码审计之PHP核心配置详解

代码审计之PHP核心配置详解1.register_globals&#xff08;全局变量注册开关&#xff09;2.allow_url_include&#xff08;是否允许包含远程文件&#xff09;3.magic_quotes_gpc&#xff08;魔术引号自动过滤&#xff09;4.magic_quotes_runtime&#xff08;魔术引号自动过滤&a…

【建议收藏】利用python基于模拟退火计算QUBO表达式(内附代码)

文章目录引言模拟退火算法模拟退火的理论过程模拟退火在优化中的应用基于python的模拟退火编码流程定义目标函数初始化状态迭代寻找最优完整代码模拟退火在求解QUBO表达式中的应用结束语引言 在计算QUBO解的过程中&#xff0c;通常需要利用不同的优化算法来计算其结果。 在本…

2023 年十大 API 管理趋势

作者郑玩星&#xff0c;API7.ai 技术工程师。 阅读原文 什么是 API&#xff1f;什么是 API 管理&#xff1f; 近期&#xff0c;AIGC&#xff08;AI Generated Content&#xff0c;生成式人工智能&#xff09;在各行业的应用日趋普及。AIGC 服务提供商通过 API 向外部提供其内…

18 隐私模式下面发送 http 请求不成功

前言 是这样的一个情况, 最近 我们服务存在这样的一个问题 是在登录界面, 假设我用户名 或者 密码输入错误, 能够得到真确的结果, 拿到了 正常的 http 响应, 回来 "用户名 或者 密码 不正确 " 但是 假设是在 隐私模式下面, 同样的输入, 同样的服务, 但是结果 不一…

VMware ESXi 7.0 U3l macOS Unlocker OEM BIOS (标准版和厂商定制版)

VMware ESXi 7.0 U3l macOS Unlocker & OEM BIOS (标准版和厂商定制版) 提供标准版和 Dell (戴尔)、HPE (慧与)、Lenovo (联想)、Inspur (浪潮)、Cisco (思科) 定制版镜像 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-esxi-7-u3-oem/&#xff0c;查看最新版…

C++---状态压缩dp---小国王(每日一道算法2023.4.15)

注意事项&#xff1a; 状压dp难度警告&#xff01; 本题为"状态压缩dp—蒙德里安的梦想"的近似题&#xff0c;建议先阅读这篇文章并理解。 题目&#xff1a; 在 nn 的棋盘上放 k 个国王&#xff0c;国王可攻击相邻的 8 个格子&#xff0c;求使它们无法互相攻击的方案…

1~5年的软件测试工程师,该学习哪些知识实现涨薪20K?

工作已经8年有余&#xff0c;这8年里特别感谢技术管理人员的器重&#xff0c;以及同事的帮忙&#xff0c;学到了不少东西。这8年里走过一些弯路&#xff0c;也碰到一些难题&#xff0c;也受到过做为一名测试却经常为系统维护和发布当救火队员的苦恼。遂决定梳理一下自己所学的东…

华为暑期实习

前言&#xff1a; 多行数据需要输入的时候可以用下面的结构&#xff1a; while True:try:n int(input())s input().split()num []for i in s:num.append(int(i))k int(input())print(num[n-k])except:break输入两组数据&#xff1a; 1 8108 17 2542 4218 9064 4908 1526 …

【WLSM、FDM状态估计】电力系统状态估计研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

实验二 图像空间域频率域滤波

一&#xff0e;实验目的&#xff1a; 1. 模板运算是空间域图象增强的方法&#xff0c;也叫模板卷积。 &#xff08;1&#xff09;平滑&#xff1a;平滑的目的是模糊和消除噪声。平滑是用低通滤波器来完成&#xff0c;在空域中全是正值。 &#xff08;2&#xff09;锐化&…

ChatGPT实战100例 - (01) 秒出思维导图

文章目录ChatGPT实战100例 - (01) 秒出思维导图一、需求与思路1. 需求&#xff1a;快速的头脑风暴2. 思路&#xff1a;生成markdown然后转化嗯二、生成markdown语法的思维导图1. 问题2. 回答三、把markdown文本转换成思维导图1. 转换2. 下载ChatGPT实战100例 - (01) 秒出思维导…

Nature Communications|评估推进基于网络的蛋白质-蛋白质相互作用预测的社区工作

题目&#xff1a;Assessment of community efforts to advance network-based prediction of protein–protein interactions 文献来源&#xff1a;Nature Communications | (2023) 14:1582 4 代码&#xff1a;https://github.com/spxuw/PPI-Prediction-Project 内容&#x…

英语基础:四级431、六级没过,考研英语78分经验分享 (23考研)

前言 博主备考时的英语基础&#xff1a;英语四级431分, 六级没过 研究生英语二分数&#xff1a;78分 ps&#xff1a;也许这个分数段不是一些大佬的目标分数 (80)&#xff0c;本篇文章的目的只是帮助一些英语基础差的同学&#xff0c;提供一些备考经验。 一、基础阶段 时间&…

AI与未来文明:人工智能能否重塑人类文化,改变社会生活?

哈喽&#xff0c;大家好&#xff0c;我是木易巷&#xff01; 今天我想和大家深入探讨一个备受关注、广泛讨论的话题&#xff1a;人工智能&#xff08;AI&#xff09;及其对我们人类未来发展的影响&#xff0c;人工智能能否重塑人类文化&#xff0c;改变社会生活&#xff1f; 我…

JVM参数

GC参数 年轻代老年代参数SerialSerial Old-XX:UseSerialGCParallel ScavengeParallel Old-XX:UseParallelGC -XX:UseParallelOldGCParallel NewCMS-XX:UseParNewGC -XX:UseConcMarkSweepGCG1G1-XX:UseG1GCZGCZGC-XX:UseZGC jdk默认GC新生代老年代默认参数jdk8Parallel Scaven…

Ps 毛玻璃效果

哈喽&#xff0c;各位小伙伴&#xff01;今天我们来学习一下如何制作毛玻璃效果&#xff1f; 复制图层 导入一张图片&#xff0c;Ctrlj复制一层&#xff0c;右键—智能对象&#xff08;目的&#xff1a;方便后期更换图片&#xff09; 画矩形 画矩形(不要描边)&#xff0c;…

2023年提供优质客户服务的9种专家方法

随着我们进入 2023年&#xff0c;客户服务从未如此重要。研究表明&#xff0c;86%的客户会为良好的客户服务多支付高达 25%的费用。拥有最佳客户体验的客户比客户体验不佳的客户多花费 140%。 1.确保您拥有一支出色的客户服务团队 创造出色的客户体验意味着拥有合适的团队。但出…

Android 屏幕刷新机制与优化方案~

作者&#xff1a;阿健君 屏幕刷新机制 基本概念 刷新率&#xff1a;屏幕每秒刷新的次数&#xff0c;单位是 Hz&#xff0c;例如 60Hz&#xff0c;刷新率取决于硬件的固定参数。帧率&#xff1a;GPU 在一秒内绘制操作的帧数&#xff0c;单位是 fps。Android 采用的是 60fps&am…