数据结构--二叉树的顺序实现(堆实现)

引言

在计算机科学中,二叉树是一种重要的数据结构,广泛应用于各种算法和程序设计中。本文将探讨二叉树的顺序实现,特别是堆的实现方式。

一、树

1.1树的概念与结构

树是⼀种⾮线性的数据结构,它是由 n(n>=0)  个有限结点组成⼀个具有层次关系的集合。把它叫做
树是因为它看起来像⼀棵倒挂的树,也就是说它是根朝上,⽽叶朝下的。
有⼀个特殊的结点,称为根结点,根结点没有前驱结点。
除根结点外,其余结点被分成 M(M>0) 个互不相交的集合 T1、T2、……、Tm ,其中每⼀个集合 Ti(1 <= i <= m) ⼜是⼀棵结构与树类似的⼦树。每棵⼦树的根结点有且只有⼀个前驱,可以有 0 个或多个后继。因此,树是递归定义的。

树形结构中,⼦树之间不能有交集,否则就不是树形结构
⾮树形结构:

总结:

⼦树是不相交的(如果存在相交就是图了,图以后得课程会有讲解)
除了根结点外,每个结点有且仅有⼀个⽗结点
⼀棵N个结点的树有N-1条边

1.2树的基本术语 

  • ⽗结点/双亲结点:若⼀个结点含有⼦结点,则这个结点称为其⼦结点的⽗结点; 如上图:A是B的⽗结点

  • ⼦结点/孩⼦结点:⼀个结点含有的⼦树的根结点称为该结点的⼦结点; 如上图:B是A的孩⼦结点

  • 结点的度:⼀个结点有⼏个孩⼦,他的度就是多少;⽐如A的度为6,F的度为2,K的度为0

  • 树的度:⼀棵树中,最⼤的结点的度称为树的度; 如上图:树的度为 6

  • 叶⼦结点/终端结点:度为 0 的结点称为叶结点; 如上图: BCHI... 等结点为叶结点

  • 分⽀结点/⾮终端结点:度不为 0 的结点; 如上图: DEFG... 等结点为分⽀结点

  • 兄弟结点:具有相同⽗结点的结点互称为兄弟结点(亲兄弟); 如上图: BC 是兄弟结点

  • 结点的层次:从根开始定义起,根为第 1 层,根的⼦结点为第 2 层,以此类推;

  • 树的⾼度或深度:树中结点的最⼤层次; 如上图:树的⾼度为 4

  • 结点的祖先:从根到该结点所经分⽀上的所有结点;如上图: A 是所有结点的祖先

  • 路径:⼀条从树中任意节点出发,沿⽗节点-⼦节点连接,达到任意节点的序列;⽐如A到Q的路径为: A-E-J-Q;H到Q的路径H-D-A-E-J-Q

  • ⼦孙:以某结点为根的⼦树中任⼀结点都称为该结点的⼦孙。如上图:所有结点都是A的⼦孙

  • 森林:由 m(m>0)棵互不相交的树的集合称为森林;

1.3树的表示法

孩⼦兄弟表⽰法:
树结构相对线性表就⽐较复杂了,要存储表⽰起来就⽐较⿇烦了,既然保存值域,也要保存结点和结点之间的关系,实际中树有很多种表⽰⽅式如:双亲表⽰法,孩⼦表⽰法、孩⼦双亲表⽰法以及孩⼦兄弟表⽰法等。我们这⾥就简单的了解其中最常⽤的孩⼦兄弟表⽰法
struct TreeNode
 {
	 struct Node* child; 	// 最左边的孩子结点
	 struct Node* brother; 	// 指向其右边的下一个兄弟结点
	 int data; 				// 结点中的数据域
};

1.4树形结构实际运⽤场景

⽂件系统是计算机存储和管理⽂件的⼀种⽅式,它利⽤树形结构来组织和管理⽂件和⽂件夹。在⽂件系统中,树结构被⼴泛应⽤,它通过⽗结点和⼦结点之间的关系来表⽰不同层级的⽂件和⽂件夹之间的关联。

二、二叉树 

2.1二叉树的概念与结构

二叉树(binary tree) 是一种非线性数据结构,代表“祖先”与“后代”之间的派生关系,体现了“一分为二” 的分治逻辑。与链表类似,二叉树的基本单元是节点,每个节点包含值、左子节点引用和右子节点引用。

总结:
1. ⼆叉树不存在度⼤于 2 的结点
2. ⼆叉树的⼦树有左右之分,次序不能颠倒,因此⼆叉树是有序树
注意:对于任意的⼆叉树都是由以下⼏种情况复合⽽成的

2.2二叉树的基本术语

  • 根节点(root node) :位于二叉树顶层的节点,没有父节点。
  • 叶节点(leaf node):没有子节点的节点,其两个指针均指向 None
  • 节点所在的 层(level) :从顶至底递增,根节点所在层为 1 。
  • 节点的度(degree) :节点的子节点的数量。在二叉树中,度的取值范围是 0、1、2 。
  • 二叉树的高度(height) :从根节点到最远叶节点所经过的边的数量。
  • 节点的深度(depth) :从根节点到该节点所经过的边的数量。
  • 节点的高度(height) :从距离该节点最远的叶节点到该节点所经过的边的数量。

 2.3特殊二叉树

1.完美二叉树(满二叉树)

完美二叉树(perfect binary tree) 所有层的节点都被完全填满。在完美二叉树中,叶节点的度
0 ,其余所有节点的度都为 2 ;若树的高度为 ,则节点总数为 2 ℎ+1 − 1 ,呈现标准的指数级关系,反映了自然界中常见的细胞分裂现象。

2. 完全二叉树
完全二叉树(complete binary tree) 只有最底层的节点未被填满,且最底层节点尽量靠左填充。

2.4二叉树的存储结构

⼆叉树⼀般可以使⽤两种结构存储,⼀种顺序结构,⼀种链式结构。

2.4.1顺序结构

顺序结构存储就是使⽤数组来存储,⼀般使⽤数组只适合表⽰完全⼆叉树 ,因为不是完全⼆叉树会有空间的浪费,完全⼆叉树更适合使⽤顺序结构存储。

2.3.2 链式结构

⼆叉树的链式存储结构是指,⽤链表来表⽰⼀棵⼆叉树,即⽤链来指⽰元素的逻辑关系。 通常的⽅法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别⽤来给出该结点左孩⼦和右孩⼦所在的链结点的存储地址 。链式结构⼜分为 ⼆叉链 三叉链 。(红⿊树等会⽤到三叉链。)

三、实现顺序结构二叉树 

⼀般堆使⽤顺序结构的数组来存储数据,堆是⼀种特殊的⼆叉树,具有⼆叉树的特性的同时,还具备其他的特性。

3.1堆的概念与结构

堆是一种完全二叉树,具有以下性质:

  • 最大堆:每个节点的值都大于或等于其子节点的值。

  • 最小堆:每个节点的值都小于或等于其子节点的值。

堆常用于实现优先队列,因为它能有效地支持插入和删除操作。

总结
堆中某个结点的值总是不⼤于或不⼩于其⽗结点的值;
堆总是⼀棵完全⼆叉树。

3.2堆的实现

我们以小堆为例进行实现:

3.2.1存储结构

二叉树的顺序存储通常使用数组来实现。对于一个节点在数组中的索引 i,可以通过以下方式找到其父节点和子节点的索引:

  • 父节点(i - 1) / 2(取整)
  • 左子节点2 * i + 1
  • 右子节点2 * i + 2
typedef struct Heap
{
	DataType *arr;
	int size;
	int capacity;
}HP;

这里可以看到堆的底层结构和动态顺序表一样。

3.2.2相关操作

1.初始化

//初始化
void HPInit(HP* p)
{
	assert(p);
	p->arr = NULL;
	p->size = p->capacity = 0;
}

2.销毁 

//销毁
void HPDestory(HP* p)
{
	assert(p);
	if (p->arr)
	{
		free(p->arr);
	}
	p->arr = NULL;
	p->size = p->capacity = 0;
}
Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

3.向上调整

💡 向上调整算法
先将元素插⼊到堆的末尾,即最后⼀个孩⼦之后
插⼊之后如果堆的性质遭到破坏,将新插⼊结点顺着其双双亲往上调整到合适位置即可

//堆的向上调整
void AdjustUp(DataType* arr, int child)
{
	int parent = (child - 1) / 2;//父节点
	while(child>0)//注意child可能会被调整到根节点,这时候就不能再调整了
	{
		if (arr[child] < arr[parent])//如果条件语句不成立,就说明堆已经成型
		{
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;//循环以上步骤
		}
		else
		{
			break;
		}
	}
}

4.堆的插⼊

将新数据插⼊到数组的尾上,再进⾏向上调整算法,直到满⾜堆。

//插入
void HPPush(HP* p, DataType x)
{
	assert(p);
	if (p->size == p->capacity)//判断空间是否足够
	{
		//扩容
		int NewCap = p->capacity == 0 ? 4 : 2 * p->capacity;
		DataType* tmp = (DataType*)realloc(p->arr, NewCap * sizeof(DataType));
		if (tmp == NULL) 
		{
			perror("realloc fail!");
			exit(1);
		}
		p->arr = tmp;
		p->capacity = NewCap;
	} 
	p->arr[p->size] = x;
	AdjustUp(p->arr, p->size);
	++p->size;
}

5.向下调整法

💡 向下调整算法
将堆顶元素与堆中最后⼀个元素进⾏交换
删除堆中最后⼀个元素
将堆顶元素向下调整到满⾜堆特性为⽌
向下调整算法有⼀个前提:左右⼦树必须是⼀个堆,才能调整。

//堆的向下调整
void AdjustDwon(DataType* arr, int parent, int n)
{
	int child = parent * 2 + 1;//左孩子
	while (child < n) 
	{
		//寻找左右孩子最小的那个
		if (child + 1 < n && arr[child] > arr[child + 1])
		{
			child++;
		}
		//这里和向上调整就一样了,比较,交换,循环
		if (arr[child] < arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

 6.堆的删除

删除堆是删除堆顶的数据,将堆顶的数据根最后⼀个数据⼀换,然后删除数组最后⼀个数据,再进⾏向下调整算法。

//删除,出堆顶数据
void HPPop(HP* p)
{
	assert(p && p->size);
	Swap(&p->arr[0], &p->arr[p->size - 1]);
	--p->size;
	AdjustDwon(p->arr, 0, p->size);
}

7.判空

//判空
bool HPEmpty(HP* p)
{
	assert(p);
	return p->size == 0;
}

8.返回堆顶元素

//返回堆顶元素
DataType HPTop(HP* p)
{
	assert(p && p->size);
	return p->arr[0];
}

四、完整代码

Heap.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
//定义堆的结构--数组
typedef int DataType;
typedef struct Heap//小堆为例
{
	DataType *arr;
	int size;
	int capacity;
}HP;
//初始化
void HPInit(HP* p);
//销毁
void HPDestory(HP* p);
//插入
void HPPush(HP* p,DataType x);
//删除,出堆顶数据
void HPPop(HP* p);
//判空
bool HPEmpty(HP* p);
//返回堆顶元素
DataType HPTop(HP* p);

Heap.c

#define _CRT_SECURE_NO_WARNINGS
#include"Heap.h"
//初始化
void HPInit(HP* p)
{
	assert(p);
	p->arr = NULL;
	p->size = p->capacity = 0;
}
//销毁
void HPDestory(HP* p)
{
	assert(p);
	if (p->arr)
	{
		free(p->arr);
	}
	p->arr = NULL;
	p->size = p->capacity = 0;
}
Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
//堆的向上调整
void AdjustUp(DataType* arr, int child)
{
	int parent = (child - 1) / 2;//父节点
	while(child>0)//注意child可能会被调整到根节点,这时候就不能再调整了
	{
		if (arr[child] < arr[parent])//如果条件语句不成立,就说明堆已经成型
		{
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;//循环以上步骤
		}
		else
		{
			break;
		}
	}
}
//插入
void HPPush(HP* p, DataType x)
{
	assert(p);
	if (p->size == p->capacity)//判断空间是否足够
	{
		//扩容
		int NewCap = p->capacity == 0 ? 4 : 2 * p->capacity;
		DataType* tmp = (DataType*)realloc(p->arr, NewCap * sizeof(DataType));
		if (tmp == NULL) 
		{
			perror("realloc fail!");
			exit(1);
		}
		p->arr = tmp;
		p->capacity = NewCap;
	} 
	p->arr[p->size] = x;
	AdjustUp(p->arr, p->size);
	++p->size;
}
//堆的向下调整
void AdjustDwon(DataType* arr, int parent, int n)
{
	int child = parent * 2 + 1;//左孩子
	while (child < n) 
	{
		//寻找左右孩子最小的那个
		if (child + 1 < n && arr[child] > arr[child + 1])
		{
			child++;
		}
		//这里和向上调整就一样了,比较,交换,循环
		if (arr[child] < arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
//删除,出堆顶数据
void HPPop(HP* p)
{
	assert(p && p->size);
	Swap(&p->arr[0], &p->arr[p->size - 1]);
	--p->size;
	AdjustDwon(p->arr, 0, p->size);
}
//判空
bool HPEmpty(HP* p)
{
	assert(p);
	return p->size == 0;
}
//返回堆顶元素
DataType HPTop(HP* p)
{
	assert(p && p->size);
	return p->arr[0];
}

main.c

#define _CRT_SECURE_NO_WARNINGS
#include"Heap.h"
void test01()
{
	HP hp;
	HPInit(&hp);
	int arr[] = { 17,20,10,13,19,15 };
	for (int i = 0; i < 6; i++)
	{
		HPPush(&hp, arr[i]);
  	}
	//HPPop(&hp);
	while (!HPEmpty(&hp))
	{
		printf("%d-", HPTop(&hp));
		HPPop(&hp);
	}
	HPDestory(&hp);
}
int main()
{
	test01();
	return 0;
}

五、总结

通过顺序实现的方式,我们可以高效地存储和操作二叉树。堆作为一种特殊的二叉树,提供了快速的插入和删除操作,非常适合优先队列的实现。在许多应用场景中,如任务调度、图算法等,堆结构都发挥着重要作用。

希望本文能够帮助你理解二叉树的顺序实现及堆的基本操作。继续探索数据结构的世界,会发现更多有趣的应用和挑战!

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

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

相关文章

【C++打怪之路Lv6】-- 内存管理

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文(平均质量分82)&#…

15分钟学 Python 第36天 :Python 爬虫入门(二)

Python 爬虫入门&#xff1a;环境准备 在进行Python爬虫的学习和实践之前&#xff0c;首先需要准备好合适的开发环境。本节将详细介绍Python环境的安装、必要库的配置、以及常用工具的使用&#xff0c;为后续的爬虫编写奠定坚实的基础。 1. 环境准备概述 1.1 为什么环境准备…

基于Springboot投稿和稿件处理系统设计与实现

博主介绍&#xff1a;专注于Java vue .net php phython 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟 我的博客空间发布了1000毕设题目 方便大家学习使用 感兴趣的…

数据集-目标检测系列- 货船 检测数据集 freighter>> DataBall

数据集-目标检测系列- 货船 检测数据集 freighter>> DataBall 数据集-目标检测系列- 货船 检测数据集 freighter>> DataBall 数据量&#xff1a;3k 想要进一步了解&#xff0c;请联系。 DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种…

订阅ROS2中相机的相关话题并保存RGB、深度和点云图

系统&#xff1a;Ubuntu22.04 ROS2版本&#xff1a;ROS2 humble 1.订阅ROS2中相机的相关话题并保存RGB图、深度图和点云图 ros2 topic list/stellar_1/rgb/image_raw /camera/depth/image_raw /stellar_1/points2CMakeLists.txt cmake_minimum_required(VERSION 3.15) projec…

建筑资质的未来发展趋势

&#x1f3d7;️建筑资质是建筑企业进入市场的通行证&#xff0c;它不仅关系到企业的竞争力&#xff0c;也影响着整个建筑行业的健康发展。随着政策的调整和技术的进步&#xff0c;建筑资质管理正面临着新的变革。 1. 资质管理的数字化转型&#xff1a;&#x1f310; 随着信息技…

Gaussian-splatting 项目环境配置笔记(Win11)

如果你是配置别的项目的过程中用到了3D GS相关的内容&#xff0c;然后这部分内容环境一直配不好&#xff0c;也可以跟随这个博客配一下环境&#xff0c;配完后起码3D GS部分就搞定了。 文章目录 概述项目链接&#xff1a;VS2019直接下载链接CUDA不同版本下载链接安装Condasetup…

63.5 注意力提示_by《李沐:动手学深度学习v2》pytorch版

系列文章目录 文章目录 系列文章目录注意力提示生物学中的注意力提示查询、键和值注意力的可视化使用 show_heatmaps 显示注意力权重代码示例 代码解析结果 小结练习 注意力提示 &#x1f3f7;sec_attention-cues 感谢读者对本书的关注&#xff0c;因为读者的注意力是一种稀缺…

【MATLAB2024b】安装离线帮助文档(windows)

文章目录 一、在 MATLAB 设置中安装二、从math works 网站下载ISO&#xff1a;给无法联网的电脑安装三、重要说明 版本&#xff1a;matlab 2024b&#xff08;或者大于等于2023a&#xff09; 所需空间&#xff1a;10~15 GB 平台&#xff1a;Windows 需要注册math works账号。 一…

深度学习-19-深入理解并训练自己的Tokenizer分词器

文章目录 1 tokenization是什么2 Tokenization方法简介2.1 单词级的Tokenization2.2 子词Tokenization技术2.3 举例说明2.3.1 字符级别2.3.2 词语级别2.3.3 子词级别3 训练自己的Tokenizer3.1 下载数据集3.2 huggingface的Tokenizer实现3.3 my-tokenizer.json字段说明3.4 验证一…

鸿蒙harmonyos next flutter混合开发之开发package

​​​​​​ 创建 package flutter create --templatepackage mypackage package代码如下&#xff1a; 创建hello_world.dart ///HelloWorld返回hello world 拼接param class HelloWorld {String helloWorld(String param) > "hello world ${param}"…

【视频目标分割-2024CVPR】Putting the Object Back into Video Object Segmentation

Cutie 系列文章目录1 摘要2 引言2.1背景和难点2.2 解决方案2.3 成果 3 相关方法3.1 基于记忆的VOS3.2对象级推理3.3 自动视频分割 4 工作方法4.1 overview4.2 对象变换器4.2.1 overview4.2.2 Foreground-Background Masked Attention4.2.3 Positional Embeddings 4.3 Object Me…

CSS实现服务卡片

CSS实现服务卡片 效果展示 CSS 知识点 回顾整体CSS知识点灵活运用CSS知识点 页面整体布局 <div class"container"><div class"card"><div class"box"><div class"icon"><ion-icon name"color-pal…

Mac 卸载 IDEA 流程

1、现在应用程序中删除Idea 2、进入Library目录 cd /Users/zhengzhaoxiang/Library 3、删除IntelliJIdea2023.3&#xff08;根据自己的版本而定&#xff09;记得进去看下是否删除干净了 rm -rf Logs/JetBrains/IntelliJIdea2023.3 rm -rf Preferences/com.jetbrains.intel…

蘑菇分类检测数据集 21类蘑菇 8800张 带标注 voc yolo

蘑菇分类检测数据集 21类蘑菇 8800张 带标注 v 蘑菇分类检测数据集 21类蘑菇 8800张 带标注 voc yolo 蘑菇分类检测数据集介绍 数据集名称 蘑菇分类检测数据集 (Mushroom Classification and Detection Dataset) 数据集概述 该数据集专为训练和评估基于YOLO系列目标检测模型…

python爬虫 - 初识爬虫

&#x1f308;个人主页&#xff1a;https://blog.csdn.net/2401_86688088?typeblog &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/2401_86688088/category_12797772.html 目录 前言 一、爬虫的关键概念 &#xff08;一&#xff09;HTTP请求与响应 &#xff0…

uni-app在线预览pdf

这里推荐下载pdf.js 插件 PDF.js - Browse Files at SourceForge.net 特此注意 如果报 Promise.withResolvers is not a function 请去查看版本兼容问题 降低pdf.js版本提高node版本 下载完成后 在 static 文件夹下新建 pdf 文件夹&#xff0c;将解压文件放进 pdf 文件…

基于SpringBoot+Vue的摄影社团管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

API接口开发系列文章:构建高效、安全与可扩展的API服务

前言 在当今的数字化时代&#xff0c;API&#xff08;应用程序编程接口&#xff09;已成为连接不同系统、服务和应用的核心桥梁。无论是企业内部的数据交互&#xff0c;还是面向第三方的服务开放&#xff0c;API都扮演着至关重要的角色。本系列文章将深入探讨API接口开发的各个…

【nlp自然语言】知识图谱,全文检索,自然语言nlp,数据资产标签,集成管理平台

一、项目介绍 一款全源码&#xff0c;可二开&#xff0c;可基于云部署、私有部署的企业级知识库云平台&#xff0c;一款让企业知识变为实打实的数字财富的系统&#xff0c;应用在需要进行文档整理、分类、归集、检索、分析的场景。 为什么建立知识库平台&#xff1f; 助力企业…