二叉树以及堆的实现

news2025/4/8 18:39:22

树的定义及概念

树是⼀种非线性的数据结构,它是由n(n>=0)有限结点组成⼀个具有层次关系集合。把它叫做树是因为它看起来像⼀棵倒挂的树,也就是说它是根朝上,而叶朝下的。

  • 有⼀个特殊的结点,称为根结点,根结点没有前驱结点
  • 除根结点外,其余结点被分成M(M>0) 个互不相交的集合T1、T2、……、Tm ,其中每⼀个集合Ti(1 <= i <= m) 又是⼀棵结构与树类似的⼦树。每棵子树的根结有且只有⼀个前驱,可以有0个或多个后继。因此,树是递归定义的。

在这里插入图片描述
树的性质:

  • 子树不相交
  • 除了根结点外,每个结点有且仅有一个父结点
  • 一棵N个结点的树有N-1条边

树的相关术语

  • 父结点/双亲结点若一个结点含有子结点,则这个结点称为其子结点的父结点;如上图中GJk的父结点
  • 子结点/孩子结点一个结点含有的子树的根结点称为该结点的子结点;如上图中BA的孩子结点
  • 结点的度一个结点有几个孩子结点,他的度就是多少;⽐如A的度为3,F的度为0,G的度为2
  • 树的度:⼀棵树中,最大的结点的度称为树的度;如上图树的度为3
  • 叶子结点/终端结点度为0的结点称为叶结点;如上图中的EF结点都为叶子结点
  • 分支结点/非终端结点度不为0的结点;如上图中的BG结点都为分支结点
  • 兄弟结点具有相同父结点的结点互称为兄弟结点(亲兄弟);如上图中的BC结点为兄弟结点
  • 结点的层次从根开始定义起,根为第1层,根的子结点为第2层,以此类推
  • 树的高度或深度树中结点的最大层次;如上图树的高度或深度为4
  • 结点的祖先从根到该结点所经分支上的所有结点;如上图中A是所有结点的祖先
  • 路径⼀条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列;如上图中AK的路径为A-C-G-K
  • 子孙以某结点为根的子树中任一结点都称为该结点的子孙。如上图中所有结点都是A的子孙
  • 森林m(m>0) 棵互不相交的树的集合称为森林

树的表示

孩子兄弟表示法
树结构相对线性表就比较复杂了,要存储表示起来就比较⿇烦了,既然保存值域,也要保存结点和结点之间的关系,实际中树有很多种表示方式如:双亲表示法,孩子表示法、孩子双亲表示法以及孩子兄弟表示法等。我们这⾥就简单的了解其中最常用的孩⼦兄弟表示法。

 struct TreeNode 
{ 
	struct Node* child;//左边开始的第⼀个孩⼦结点
	struct Node* brother;//指向其右边的下⼀个兄弟结点
	int data;             
};

在这里插入图片描述
在这里插入图片描述

树形结构实际运用场景

文件系统计算机存储管理文件的⼀种方式,它利用树形结构来组织和管理文件和文件夹。在文件系统中,树结构被广泛应用,它通过父结点和子结点之间的关系来表示不同层级的文件和文件夹之间的关联。
在这里插入图片描述

二叉树

概念与结构

在树形结构中,我们最常用的就是⼆叉树,⼀棵⼆叉树是结点的⼀个有限集合,该集合由⼀个根结点加上两棵别称为左子树和右子树的⼆叉树组成或者为空。
在这里插入图片描述

二叉树的性质
  • 二叉树不存在度大于2的结点
  • 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

特殊的二叉树

满二叉树

⼀个⼆叉树,如果每一个层的结点数都达到最大值,则这个⼆叉树就是满⼆叉树。也就是说,如果⼀
二叉树的层数为K,且结点总数是2^k-1,则它就是满⼆叉树。
在这里插入图片描述

完全二叉树

完全⼆叉树是效率很⾼的数据结构,完全⼆叉树是由满⼆叉树而引出来的。对于深度为K的,有n个结点的⼆叉树,当且仅当其每一个结点都与深度为K的满⼆叉树中编号从1n的结点一一对应时称之为完全二叉树。要注意的是满二叉树是一种特殊的完全二叉树
在这里插入图片描述
性质:

  • 若规定根结点的层数为1,则⼀棵⾮空⼆叉树的第i层上最多有2^(i-1)个结点
  • 若规定根结点的层数为1,则深度为h的⼆叉树的最大结点数是h^2 −1
  • 若规定根结点的层数为1,具有n个结点的满二叉树的深度( h = log2(n+1) log以2为底,n+1 为对数)

二叉树的存储

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

顺序结构

顺序结构存储就是使用数组来存储,⼀般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费,完全⼆叉树更适合使用顺序结构存储。
在这里插入图片描述

链式结构

⼆叉树的链式存储结构是指,用链表来表示⼀棵⼆叉树,即用链来指示元素的逻辑关系。通常的方法是链表中每个结点由三个域组成数据域和左右指针域左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址。链式结构⼜分为二叉链三叉链

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

实现顺序结构二叉树

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

堆的概念与结构

如果有⼀个关键码的集合K = {k0,k1 ,k2 ,…,kn } ,把它的所有元素按完全⼆叉树的顺序存储方式存储,在⼀个⼀维数组中,并满⾜:Ki<= K2∗i+1(K>=i K2∗i+1 且K <=i K2∗i+2),i = 0、1、2... ,则称为小堆(或大堆)。将根结点最大的堆叫做最大堆或大根堆,根结点最小的堆叫做小堆或小根堆。
在这里插入图片描述

堆的性质:

  • 堆中某个结点的值总是不大于或不小于父结点的值
  • 堆总是一棵完全二叉树

⼆叉树性质:
对于具有n 个结点的完全⼆叉树,如果按照从上至下从左至右的数组顺序对所有结点从0 开始编号,则对于序号为i的结点有:

  • i>0i位置结点的双亲序号:(i-1)/2i=0i为根结点编号,无双亲结点
  • 2i+1<n ,左孩子序号:2i+1,若2i+1>=n,则无左孩子结点
  • 2i+2<n ,右孩⼦序号:2i+2 ,若2i+2>=n,则无右孩子结点

堆的实现(以小根堆为例)

堆的实现分为三个文件:heap.h、heap.c、test.c

heap.h

我们需要借助数组来实现堆,因此在结构体的定义时,我们选择了动态数组

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef int HPDataType;

typedef struct Heap
{
	HPDataType* arr;
	int size;
	int capacity;
}HP;

//初始化
void HPInit(HP* php);

//销毁
void HPDestory(HP* php);

//入堆
void HPPush(HP* php, HPDataType x);

//出堆
void HPPop(HP* php);

//判空
bool HPEmpty(HP* php);

//堆头元素
HPDataType HPtop(HP* php);

heap.c

初始化(同顺序表)

#include"heap.h"

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

销毁(同顺序表)

void HPDestory(HP* php)
{
	assert(php);
	if (php->arr)
		free(php->arr);
	php->arr = NULL;
	php->size = php->capacity = 0;
}

入堆

思路:

  1. 判断数组空间是否满了,满了则需要进行扩容
  2. 将数据插入,需要判断该数据是否满足小根堆的特点
  3. 若不满足,则需要将父结点与该结点进行交互,并继续进行判断,从而实现数据向上调整,从而满足小跟读的特点
  4. size++

在这里插入图片描述

例如需要在该小根堆中插入数据5,插入完成后跟父结点进行对比,即将5与56进行对比,因为56>5,因此将56与5进行交换
在这里插入图片描述
接着判断插入的5与他的父结点10,接着再进行交换
在这里插入图片描述
发现该结点已经变成根节点,已满足小根堆结点

void swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

void AdjustUp(HPDataType* arr,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;
		}
	}
}

//入堆
void HPPush(HP* php, HPDataType x)
{
	assert(php);
	if (php->size == php->capacity)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->arr, sizeof(HPDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		php->capacity = newcapacity;
		php->arr = tmp;
	}
	php->arr[php->size] = x;
	AdjustUp(php->arr, php->size);
	php->size++;
}

出堆

思路:

  1. 将根结点与最后的结点进行交换
  2. 将size–
  3. 向下调整,使堆满足小根堆的条件

在这里插入图片描述
例如要对该堆进行出堆操作,则需将56与5进行交换,由于size–,因此5不进入向下调整
在这里插入图片描述
取根节点的子节点,将它的左右孩子结点进行对比,将小的孩子结点与根节点进行交换
在这里插入图片描述
发现满足小根堆的条件,调整结束

void AdjustDown(HPDataType* 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[parent] > arr[child])
		{
			swap(&arr[parent], &arr[child]);
			parent = child;
			child= parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//出堆
void HPPop(HP* php)
{
	assert(php && php->size);
	swap(&php->arr[0],&php->arr[php->size-1]);
	php->size--;
	AdjustDown(php->arr, 0, php->size);
}

判空

bool HPEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}

寻找堆头元素

HPDataType HPtop(HP* php)
{
	assert(php && php->size);
	return php->arr[0];
}

test.c

#include"heap.h"

void Test()
{
	HP hp;
	HPInit(&hp);
	int arr[] = { 17,20,10,13,19,15 };
	for (int i = 0; i < 6; i++)
	{
		HPPush(&hp, arr[i]);
	}


	while (!HPEmpty(&hp))
	{
		printf("%d ", HPtop(&hp));
		HPPop(&hp);
	}


	HPDestory(&hp);
}

int main()
{
	Test();
	return 0;
}

请添加图片描述
入堆操作成功
请添加图片描述
出堆成功

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

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

相关文章

[Meachines] [Easy] Admirer Adminer远程Mysql反向+Python三方库函数劫持权限提升

信息收集 IP AddressOpening Ports10.10.10.187TCP:21,22,80 $ nmap -p- 10.10.10.187 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 21/tcp open ftp vsftpd 3.0.3 22/tcp open ssh OpenSSH 7.4p1 Debian 10deb9u7 (protocol 2.0) | ssh-hostkey: | …

Redis:十大数据类型

键&#xff08;key&#xff09; 常用命令 1. 字符串&#xff08;String&#xff09; 1.1 基本命令 set key value 如下&#xff1a;设置kv键值对&#xff0c;存货时长为30秒 get key mset key value [key value ...]mget key [key ...] 同时设置或者获取多个键值对 getrange…

万物互联,触手可及“2024南京智慧城市,物联网,大数据展会”

在金秋送爽的11月&#xff0c;南京这座历史悠久而又充满活力的城市&#xff0c;即将迎来一场科技盛宴——2024南京智慧城市、物联网、大数据展会。这不仅是一场技术的集会&#xff0c;更是未来生活蓝图的预览&#xff0c;它汇聚了全球顶尖的科技企业、创新者及行业精英&#xf…

制作PE启动U盘 预防电脑无法正常开机进入系统

PE 是一种简化版的便携式操作系统&#xff0c;它可以直接装载在 U 盘里运行。通过它我们能做非常多的应急操作&#xff0c;比如删除文件、卸载软件、拷贝数据、格式化硬盘、重装系统等。 在电脑无法正常开机进入系统&#xff0c;身边又没有其他电脑时&#xff0c;手头有个 PE …

Corsearch 用 ClickHouse 替换 MySQL 进行内容和品牌保护

本文字数&#xff1a;3357&#xff1b;估计阅读时间&#xff1a;9 分钟 作者&#xff1a;ClickHouse Team 本文在公众号【ClickHouseInc】首发 Chase Richards 自 2011 年在初创公司 Marketly 担任工程负责人&#xff0c;直到 2020 年公司被收购。他现在是品牌保护公司 Corsear…

【Linux】-----工具篇(编译器gcc/g++,调试器gdb)

目录 一、gcc/g 简单认识 程序的翻译过程认识gcc 预处理(宏替换) 编译 汇编 链接 宏观认识 如何理解&#xff08;核心&#xff09; 什么是链接&#xff1f; 链接的分类 二、gdb 基本的认识 基本操作及指令 安装gdb 启动gdb ​编辑 显示源代码(list) 运行程序…

网友提问:桌面与web开发哪个难度更大?

关于桌面应用开发与Web开发哪个难度更大的问题&#xff0c;实际上并没有绝对的答案&#xff0c;因为这取决于具体的开发任务、所使用的工具和技术栈等因素。不过&#xff0c;我们可以从几个方面来进行比较&#xff1a; 技术栈 Web开发&#xff1a; 前端通常涉及到HTML、CSS、J…

Ansible之playbook剧本编写(二)

tags 模块 可以在一个playbook中为某个或某些任务定义“标签”&#xff0c;在执行此playbook时通过ansible-playbook命令使用--tags选项能实现仅运行指定的tasks。 playbook还提供了一个特殊的tags为always。作用就是当使用always作为tags的task时&#xff0c;无论执行哪一个t…

全球奈拉滨市场规模预测:未来六年年复合增长率CAGR为1.1%

据恒州诚思研究&#xff0c;2023年全球奈拉滨市场规模大约为3.8亿元&#xff0c;预计未来六年年复合增长率CAGR为1.1%&#xff0c;到2030年市场规模将接近4.2亿元。这一增长反映了奈拉滨在全球医药行业中的重要性及其在未来发展中的潜在机会。随着科学的进一步发展和市场的扩展…

中小学汉字听写大赛方案及执行流程

一、活动背景 汉字作为中国最宝贵的文化遗产&#xff0c;在五千年的历史长河里&#xff0c;汉字以其浩瀚广博抒写着华夏历史&#xff0c;以其灵秀展示着炎黄之精神。传承汉字文明是我们的使命和主责任。为提高我校七年级学生听写汉字的能力&#xff0c;规范汉字书写的能力&…

ESD防护之电容妙用

谈到ESD防护&#xff0c;应用最广泛的是ESD/TVS管&#xff0c;对于正负4KV的pin脚不上电ESD测试&#xff0c;也可以仅仅依靠nf级电容完成ESD防护。下面以一篇实际案例进行说明。 实验要求&#xff1a;正负4KV对产品connector的Pin脚进行ESD测试&#xff0c;connector中的地脚接…

idea启动项目报:the command line via JAR manifest or via a classpath file and rerun.

解决方案 1.打开Edit Configurations&#xff0c;进去编辑&#xff0c;如下&#xff1a; 笔记配置 2.选择Modfiy options,点击Shorten command line 3.在新增的Shorten command line选项中选择JAR manifest或classpath file 4.点击保存后即可

企业如何通过红酒传达品牌理念?

在繁忙的商业世界中&#xff0c;品牌理念的传达往往是企业成功的关键。而红酒&#xff0c;这一优雅的饮品&#xff0c;不仅具有深厚的文化底蕴&#xff0c;更是品牌理念传递的很好载体。今天&#xff0c;我们就来探讨一下企业如何通过定制红酒——特别是洒派红酒&#xff08;Bo…

Java漏洞复现(ctfshow279-297)strust 漏洞复现及原理解释

Java漏洞复现 Strust原理 JavaEE--------Struts2框架-CSDN博客 Web279 struts2漏洞 S2-001是当用户提交表单数据且验证失败时&#xff0c;服务器使用OGNL表达式解析用户先前提交的参数值&#xff0c;%{value}并重新填充相应的表单数据。 这里的%{value}简单理解就是和flask的…

【计算机网络】IP分片实验

一&#xff1a;实验目的 1&#xff1a;理解IP数据报分片的工作原理。 2&#xff1a;理解IP协议报文类型和格式。 二&#xff1a;实验仪器设备及软件 硬件&#xff1a;RCMS-C服务器、网线、Windows 2019/2003操作系统的计算机等。 软件&#xff1a;记事本、WireShark、Chrom…

昇思25天学习打卡营第22天|CycleGAN图像风格迁移互换

相关知识 CycleGAN 循环生成网络&#xff0c;实现了在没有配对示例的情况下将图像从源域X转换到目标域Y的方法&#xff0c;应用于域迁移&#xff0c;也就是图像风格迁移。上章介绍了可以完成图像翻译任务的Pix2Pix&#xff0c;但是Pix2Pix的数据必须是成对的。CycleGAN中只需…

DosSnake-入土为安第八天

记录一下不能F5反编译 加密方式 密文 异或操作函数 xor_string_with_key&#xff1a; 接受两个字符串作为输入&#xff1a;待处理的 text 和 key。对每个字符进行异或操作。使用 ord(char) 获取字符的 ASCII 值&#xff0c;ord(key[i % key_length]) 是 key 中对应位置的字符的…

3D Web轻量化引擎HOOPS Communicator针对复杂大模型Web端可视化的解决方案

随着工程设计、制造和建筑领域中三维模型的日益复杂化&#xff0c;如何在Web端高效处理和展示这些大规模数据成为一大挑战。HOOPS Communicator作为一款强大的3D可视化工具&#xff0c;提供了一套针对复杂大模型的轻量化解决方案&#xff0c;涵盖了模型轻量化及格式转换、超大模…

【基础算法总结】队列 + 宽搜(BFS)

队列 宽搜BFS 1.N 叉树的层序遍历2.二叉树的锯齿形层序遍历3.二叉树最大宽度4.在每个树行中找最大值 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#…

活动报名小程序

#活动报名工具# # 活动报名小程序 ## 项目简介 一款通用的活动报名工具&#xff0c;包含活动展示&#xff0c;微信支付&#xff0c;订单管理&#xff0c;分享评价等功能。 品客聚精彩&#xff0c;有你才精彩&#xff01;不只有线下活动还可以进行线上裂变活动。 …