5.C_数据结构_树

news2024/9/20 1:32:25

概述

树的逻辑结构:

树中任何节点都可以有0个或多个直接后继节点,但最多只有一个直接前驱节点。根节点没有直接前驱节点,叶节点没有直接后继节点。 

相关名词:

  • 空树:树中没有节点
  • 节点的度数:一个节点的子树的个数
  • 树的度数:该树中节点的最大度数
  • 树叶、终端节点:度数为0的节点
  • 分支节点:度数不为0的节点
  • 内部节点:除根节点以外的分支节点
  • 路径:能够找到节点的方式,例如:A到L的路径是ABEL
  • 路径的长度:路径中的边数,边有A-B、B-E、E-L,即:长度为3
  • 节点的层数:节点的层数 = 父节点的层数+1,根节点的层数为1
  • 树的高度、深度:树中节点层数的最大值。例如:下图中深度为4
  • 祖先:路径中前面的节点为后面的祖先,例如:A是K的祖先
  • 子孙:路径中后面的节点为前面的子孙
  • 堂兄弟:层级一样但父节点不一样的节点为堂兄弟,例如:F、G
  • 兄弟:层级一样,父节点也一样的节点为兄弟,例如:E、F
  • 有序树:兄弟之间是有序的、不能交换位置的树
  • 森林:m棵互不相交的树,树去掉根节点就是森林,森林加上根节点就是树

二叉树:

二叉树是树的度数为2的有序树,即:一个父节点最多有2个子节点,且这两个节点是有顺序的。除此之外,子节点也没有指向父节点的指针。

  • 二叉树第 i 层上的节点最多有:2^(i-1)个。
  • 对于深度为k的二叉树,节点最多有:2^0 + 2^1 + ... + 2^(k-1) = 2^k -1 个
  • 满二叉树:深度为k时,有2^k-1个节点的二叉树,即每一层都是满的。
  • 完全二叉树:只有最下面两层有度数小于2的节点,且最下面的叶节点集中在最左边的位置上
  • 有n个节点的完全二叉树的深度为:log2n + 1 或 log2(n+1)

二叉树顺序存储:

编号方法是从上到下,从左到右进行编号,规定根节点的编号为1。这种方法只适用于完全二叉树,如果是不完全二叉树需要添加虚节点构成完全二叉树,这会大大增加冗余的内存使用。

假设总共有 n 个节点,当前节点的编号为 i 。则有以下结论:

  • 当编号 i ≠ 1时,有父节点,父节点的编号为 i/2
  • 当 2*i < n 时,代表有左孩子。当 2*i+1 < n 时,代表有右孩子。
  • 当 i 为奇数且不为1时,一定有左兄弟。当 i 为偶数且 i < n 时,一定有右兄弟

顺序存储的特点:

  • 二叉树的顺序存储是用数组的方式进行存储,它的空间连续。
  • 只有当二叉树为完全二叉树时,顺序存储才不会有空间浪费,否则需要先添加虚节点构成完全二叉树,再进行顺序存储。

二叉树链式存储:

由下一章详细讲解。

二叉树链式存储

1、基本内容

二叉树的链式存储是以链表的形式存储每一个节点。每一个节点都可以看成一个根,在这个根中存放了一些数据data,并且这个根中有两个树叶,即:左孩子和右孩子。具体的节点结构如下:

二叉树结点结构体声明如下:

typedef char tree_data_t;
typedef struct tree{
	tree_data_t data;     //root中存放的数据
	struct tree* left;    //左孩子
	struct tree* right;   //右孩子
}bitree;

二叉树代码的文件构成:

  • bitree.h:数据结构的定义、运算函数接口
  • bitree.c:运算函数接口的实现
  • linkqueue.c:分层遍历二叉树会用到队列
  • test.c:使用数据结构实现的应用功能代码

2、二叉树遍历代码实现

2.1 先序、中序、后序

二叉树的遍历方法:

  • 先序遍历:先访问树根,再访问左子树,最后访问右子树
  • 中序遍历:先访问左子树,再访问树根,最后访问右子树
  • 后序遍历:先访问左子树,再访问右子树,最后访问树根

可以看到这是一个递归问题,以后序遍历为例,每一个结点都是先访问左子树,再访问右子树,最后访问树根。例如下图,从A出发,先访左子树,左子树为B。之后再访问B的左子树,为空;之后访问B的右子树,为C;之后访问C的左子树为D;之后访问D的左子树,为空;之后访问D的右子树,为空;之后访问D的根,为D。这时才访问到第一个结点D。可以看到当结点为A时,是先访问左子树,访问到后,就开始第二次重复的操作。对B结点同样是先访问左子树。这个就是递归。

先序遍历代码编写思路:

从上述分析可以看出,对于二叉树的遍历,我们只需要专注与一个结点该如何遍历,之后所有结点遍历的方式都是一样的。

递归函数的前提是有一个退出条件,当我们发现需要继续往下遍历的结点为空时,这就不再需要遍历,最终递归退出。

具体代码实现如下:

/*
 * preorder:先序遍历
 * param root:根指针
 * */
void preorder(bitree* root){
	
	//停止条件:当根节点为空时,不再访问
	if(root == NULL){
		return;
	}

	printf("%c",root->data);//访问根
	preorder(root->left);   //左结点以同样的方式访问
	preorder(root->right);  //右结点以同样的方式访问
}

中序遍历与后续遍历代码:

中序遍历与后续遍历的思路与先序遍历完全一致,都是先规定好递归退出条件,之后递归的处理每一个结点。

具体代码实现如下:

/*
 * inorder:中序遍历
 * param root:根指针
 * */
void inorder(bitree* root){
	
	//停止条件:当根节点为空时,不再访问
	if(root == NULL){
		return;
	}

	inorder(root->left);    //左
	printf("%c",root->data);//根
	inorder(root->right);   //右
}

/*
 * postorder:后序遍历
 * param root:根指针
 * */
void postorder(bitree* root){
	
	//停止条件:当根节点为空时,不再访问
	if(root == NULL){
		return;
	}

	postorder(root->left);   //左
	postorder(root->right);  //右
	printf("%c",root->data); //根
}

2.2 层次遍历

二叉树的层次遍历需要用到队列。我们首先从队列中取出一个结点,这就代表访问了这个结点;之后将这个结点左右孩子非空,哪就入队列。之后循环操作,继续取出一个结点,继续将结点的左右孩子入队列。

具体代码实现如下:

/*
 * layorder:层级遍历
 * param root:根指针
 * */
void layerorder(bitree* root){
	bitree* tmp = NULL;
	linkqueue* pQueue = NULL;
	if(root == NULL){
		return;
	}
	//1.建立队列
	pQueue = queue_create();
	if(pQueue == NULL){
		return;
	}
	//2.初始化队列,将根入队
	enter_queue(pQueue,root);
	//3.开始层级遍历
	while(out_queue(pQueue,&tmp) != -1){
		if(tmp!=NULL){
			printf("%c",tmp->data);
			enter_queue(pQueue,tmp->left);
			enter_queue(pQueue,tmp->right);
		}
	}
	puts("");
}

3、二叉树创建代码实现

二叉树的创建代码,就是按照遍历的逻辑依次写入数据,比如写入的数据为char型,那就需要规定一个停止向下遍历的字符,以下代码中规定字符为' # '

具体代码实现如下:

/*
 * bitree_creat:一次性创建出一个树
 * @ret  根的指针
 * */
bitree* bitree_create(void){

	char data = '#';
	bitree* root = NULL;

	//停止条件:规定data=#时代表结点不存在
	scanf("%c",&data);
	if(data == '#'){
		return NULL;
	}
	//结点存在,申请根结点空间
	root = (bitree*)malloc(sizeof(bitree));
	if(root == NULL){
		printf("malloc err\n");
		return NULL;
	}
	root->data = data;
	//初始化左右孩子
	root->left = bitree_create();
	root->right = bitree_create();
	return root;
}

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

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

相关文章

【2025】基于微信小程序的人工智能课程学习平台的设计与实现(源码+文档+解答)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

优化算法(四)—蚁群算法(附MATLAB程序)

蚁群算法&#xff08;Ant Colony Optimization, ACO&#xff09;是一种模拟蚂蚁觅食行为的优化算法&#xff0c;由Marco Dorigo于1990年提出。它利用了蚂蚁在寻找食物的过程中通过释放信息素来相互影响的机制&#xff0c;以找到最优解或接近最优解。蚁群算法特别适用于解决组合…

workbench的使用

connection name 是可以任意取的 Hostname 是数据库的地址&#xff0c;本地的话就默认是127.0.0.1 port是端口 选择store in value来存储密码 点击测试连接test connection 单击就可以登录&#xff0c;如果需要编辑的话&#xff0c;右键选择edit connection 可以选择删除账…

MD5、SHA256哈希值生成验证工具-生成文件的“指纹ID”-调用了微软.Net Framework里的加密工具来生成哈希值

MD5、SHA256等哈希值生成工具通常用来验证文件的完整性&#xff0c;或者说是生成文件的“指纹ID”。 Windows系统下调用哈希工具&#xff0c;要用命令提示符cmd调用&#xff0c;生成和比较不太方便。我编写了一个小工具&#xff0c;将文件拖拽到软件界面即可生成比较。 下载地址…

Vue.js与Flask/Django后端配合详细讲解

✨博客主页&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客内容》&#xff1a;.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 &#x1f4e2;博客专栏&#xff1a; https://blog.csdn.net/m0_63815035/cat…

如何在没有备份的情况下恢复 Mac 上丢失的数据

Mac 是您数字世界的中心。它上面可能保存着照片和视频等回忆&#xff0c;以及您不再联系的朋友和家人发来的旧电子邮件。您可能花了数小时导入整个 CD 收藏。您还可能保存着重要文档&#xff0c;例如演示文稿和工作文件、家庭账户或学校或大学的作业。 如果由于某种原因您丢失…

【C++】C++11-包装器

目录 1、function包装器 2、function包装器包装成员函数指针 2.1 静态成员函数 2.2 非静态成员函数 3、bind包装器 3.1 调整参数顺序 3.2 调整参数个数 1、function包装器 包装器是用来包装可调用对象的&#xff0c;这里的可调用对象主要有函数指针、仿函数、lambda表达…

CSS渐变设计指南

CSS渐变设计指南 背景渐变文字渐变SVG渐变 背景渐变 开发界面时&#xff0c;渐变的图像会相比固定颜色的图形更加富有层次感与有趣。使用CSS可以轻松地为文本添加渐变效果。 实现CSS背景色渐变&#xff0c;可以使用CSS3的 background-image 属性结合 linear-gradient() 函数。…

智谱清影 -CogVideoX-2b-部署与使用,带你揭秘生成6s视频的极致体验!

文章目录 1 效果展示2 CogVideoX 前世今生3 CogVideoX 部署实践流程3.1 创建丹摩实例3.2 配置环境和依赖3.3 模型与配置文件3.4 运行4 遇到问题 1 效果展示 A street artist, clad in a worn-out denim jacket and a colorful bandana, stands before a vast concrete wall in …

JavaScript基础学习:预解析机制

JavaScript基础学习&#xff1a;预解析机制 前言 在 JavaScript 的世界里&#xff0c;代码的执行并不是简单地从上到下按顺序进行的。 在实际执行之前&#xff0c;JavaScript 引擎会进行一个特殊的阶段&#xff0c;称为“预解析”。 这一阶段对于理解 JavaScript 的行为至关…

2025武汉国际半导体产业与电子技术博览会

时间&#xff1a;2025年5月14日-16日地点&#xff1a;武汉中国光谷科技会展中心 展会简介&#xff1a; 为了推动中西部地区电子信息产业的跨越式发展&#xff0c;促进先进技术在中西部地区的创新应用&#xff0c;由中国光电子发展大会组委会联合沃森展览共同打造的2025 武汉国…

网络安全 DVWA通关指南 DVWA Stored Cross Site Scripting (存储型 XSS)

DVWA Stored Cross Site Scripting (存储型 XSS) 文章目录 DVWA Stored Cross Site Scripting (存储型 XSS)XSS跨站原理存储型 LowMediumHighImpossible 参考文献 WEB 安全靶场通关指南 XSS跨站原理 当应用程序发送给浏览器的页面中包含用户提交的数据&#xff0c;但没有经过适…

Yocto - 使用Yocto开发嵌入式Linux系统_01 前言

Embedded Linux Development Using Yocto Project: Leverage the power of the Yocto Project to build efficient Linux-based products, Third Edition By: Otavio Salvador, Daiane Angolini Overview of this book Yocto 项目是开发可靠的嵌入式 Linux 项目的行业标准。与…

C++ | Leetcode C++题解之第405题数字转换为十六进制数

题目&#xff1a; 题解&#xff1a; class Solution { public:string toHex(int num) {if (num 0) {return "0";}string sb;for (int i 7; i > 0; i --) {int val (num >> (4 * i)) & 0xf;if (sb.length() > 0 || val > 0) {char digit val …

内存管理(C++版)

C/C内存分布 程序经过编译生成可执行的二进制程序&#xff0c;我们可以把虚拟进程地址分为以下四个空间&#xff1a;栈&#xff0c;堆&#xff0c;常量区&#xff0c;静态区。这四个区里面存贮的也是不一样的内容。 各个区域所存储内容的说明 栈/堆栈&#xff1a;用于建立函…

C++—string类接口与用法大总结(其中涉及STL基础)

目录 1.string类的本质 2.string类的构造 1.普通构造 2.功能型构造 1.拷贝构造功能型 2.带参构造功能型 3.其余构造 3.operator[] 4.迭代器&#xff08;iterator&#xff09; 1.概念 2.改变string对象本身 3.正向迭代器&#xff08;iterator&#xff09; 4.反向迭代…

基于springboot的驾校预约管理系统的设计与实现 (含源码+sql+视频导入教程)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于springboot的驾校预约管理系统5拥有三种角色&#xff1a;管理员、教练、学员 管理员&#xff1a;学员管理、教练管理、车辆管理、车辆关联、维修管理等 教练&#xff1a;学员查看/毕…

通过Python代码发送量化交易信号邮件通知

量化交易利用数学模型和计算机算法来分析市场数据,并生成交易信号,本文将介绍如何使用Python编写一个简单的脚本,通过发送邮件通知量化交易信号。 开启SMTP服务 首先要在发件箱的邮件设置中,将POP3/SMPT服务开启,记录下授权密码,在本地可通过此密码登录,注意有效期和保…

总结拓展十:SAP开发计划(下)

第一节 接口功能开发说明书设计 1、软件系统接口作用 答&#xff1a;系统接口&#xff0c;是实现系统间数据传输的功能。 2、软件系统接口特点 1&#xff09;采用Web Service技术作为平台&#xff0c;有众多的数据传输协议标准&#xff0c;通过API与外界交流数据。 2&…