数据结构初阶之二叉树的详细解析

个人主页:点我进入主页

专栏分类:C语言初阶      C语言程序设计————KTV       C语言小游戏     C语言进阶

C语言刷题       数据结构初阶    Linux

欢迎大家点赞,评论,收藏。

一起努力,共赴大厂。

目录

1.前言 

2.二叉树各个功能代码实现

2.1二叉树结构体

2.2二叉树的前序遍历 

2.3中序遍历 

2.4后序遍历

2.5计算二叉树节点个数

2.6计算二叉树叶子节点的个数 

2.7计算二叉树的深度

2.8计算第k层的节点个数

2.9层序遍历

2.10层序遍历变式

2.11判断是否为完全二叉树

2.12二叉树内存释放

2.13树的创建

3.二叉树的性质

4.总结


1.前言 

        我在前面写过关于顺序表,栈,队列,堆的存储结构,现在我们还有一种一对多的存储结构树,在堆的博客中我写过一些树的概念,树的增删查改在我们的应用中并不实用,其中有用的是查找树,但是查找树的实现我们还没有能力去实现,树的实现可以用顺序表实现也可以用链表去实现,这次我们用链式二叉树去实现,利用顺序表实现可以看堆的内容。在这篇文章中我主要给大家带来关于二叉树的创建,树的一些性质,树的前序中序后序层序遍历,求树的节点个数,叶子节点个数,树的深度,第k层节点的个数,判断是不是完全二叉树,在这些中大部分需要用递归,我会给搭建展示部分功能的递归展开图来帮助大家理解,在学习这写内容中我建议大家可以会回忆一下递归的内容,是不是看到递归就觉得畏惧吗?其实我们只需要多去感受一下其中的思路与思想,不用过多的去畏惧递归,接下来就让我们看看其中是如何用递归去实现吧。

2.二叉树各个功能代码实现

2.1二叉树结构体

typedef struct BiTreeNode {
	int val;
	struct BiTreeNode* left, * right;
}BTNode;

结构体的内容包括结构体的内容,指向二叉树的左孩子的指针,指向二叉树的右孩子的指针。我给大家来看一下二叉树的大概的模型

2.2二叉树的前序遍历 

void PrevorderBTNode(BTNode* root)
{
	if (root == NULL)
		return;
	printf("%d ", root->val);
	PrevorderBTNode(root->left);
	PrevorderBTNode(root->right);
}

例如我们利用上面的二叉树进行模拟

我们可以根据代码展开图进行一步步实现代码实现的过程,最好我们自己去画一画代码展开图这样对于我们去了解递归会有非常好的作用。

2.3中序遍历 

void InorderBTNode(BTNode* root)
{
	if (root == NULL)
		return;
	InorderBTNode(root->left);
	printf("%d ", root->val);
	InorderBTNode(root->right);
}

我们的代码展开图如下

 我们可以看到我们的中序遍历代码和前序遍历代码大致相同,相差的只是代码的顺序,我们可以将大部分二叉树的递归可以表示为根节点,左孩子右孩子,左子树右子树和根节点,左孩子右孩子这两种,这非常有用是一种分治的思想。

2.4后序遍历

void PostorderBTNode(BTNode* root)
{
	if (root == NULL)
		return;
	PostorderBTNode(root->left);
	PostorderBTNode(root->right);
	printf("%d ", root->val);
}

在这里我们不给代码展开图了,大家可以自己去画一画代码展开图。

2.5计算二叉树节点个数

int BTreeSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	return BTreeSize(root->left) + BTreeSize(root->right) + 1;
}

我们想到二叉树的递归内容可以表示为根节点,左孩子右孩子,左子树右子树或根节点,左孩子右孩子,我们可以看成根节点,左子树右子树,当根节点为空时我们返回0,我们分为左子树和右子树所以我们返回BTreeSize(root->left) + BTreeSize(root->right) + 1进行递归,我们的递归展开图可以画为

2.6计算二叉树叶子节点的个数 

        我们可以根据根据根节点,左子树右子树进行分治,当我们的根节点为空时返回0,当左孩子和右孩子为空是叶子节点返回1,对于左子树和右子树我们进行递归。

int BTreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	if (root->left == NULL && root->right == NULL)
		return 1;
	return BTreeLeafSize(root->left) + BTreeLeafSize(root->right);
}

递归展开图和上面的相似,大家可以自己去画一画。

2.7计算二叉树的深度

 我们可以根据根据根节点,左子树右子树进行分治,当根节点为空时返回0,然后进行递归。

int BTreeDeap(BTNode* root)
{
	if (root == NULL)
		return 0;
	return (int)fmax(BTreeDeap(root->left), BTreeDeap(root->right)) + 1;
}

2.8计算第k层的节点个数

int BTreeLeafkSize(BTNode* root,int k)
{
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return BTreeLeafkSize(root->left, k-1) + BTreeLeafkSize(root->right, k-1);
}

当我们的根节点是空时我们返回0,当我们的k变成1时我们返回1,根据左子树右子树进行分治每次都让k-1。

2.9层序遍历

void Levelorder(BTNode* root)
{
	Queue queue;
	QueueInit(&queue);
	if (root)
	{
		QueuePush(&queue, root);
	}
	while (!QueueEmpty(&queue))
	{
		BTNode* prev = top(&queue) ;
		QueuePop(&queue);
		if (prev->left)
			QueuePush(&queue, prev->left);
		if (prev->right)
			QueuePush(&queue, prev->right);
		printf("%d ", prev->val);
	}
}

在层序遍历中我们利用队列进行存储,先将非空的根节点进行插入,进行循环队列不为空进行循环,利用一个二叉树的指针指向队头的元素(队列里的元素存的是二叉树的节点时结构体的指针所以我们可以用二叉树的指针进行指向),然后出队,入指针的非空左孩子右孩子,每次打印指针对应的值。

2.10层序遍历变式

        如果我们想每层打印时打印完每次会输出一个换行,这时候我们应该如何作呢?我们首先想到的是再搞一个队列,存放第一个队列元素是第几层,但是我们c语言去实现队列是非常麻烦的,连结构体都需要我们去重新设定,那我们应该如何去做呢?在我们的层序遍历中你有没有注意到我们的队列中总是存在全部的一层元素或者一层与下一层的元素这两种情况,什么时候会出现只有一层的元素呢?那就是上一层全部出队了,这便是我们的突破点,当我们将非空根节点入队后我们引入一个变量存放队中的元素的个数然后进入循环,此时这个变量就是一层元素的个数,我们每次出一个元素就让这个变量减1,这也就是我们的循环条件,循环结束后我们重新计算这个变量的值,这时候队中还是只有一层全部的节点,此时变量的值就是队中元素的个数。

2.11判断是否为完全二叉树

bool BinaryTreeComplete(BTNode* root)
{
	Queue queue;
	QueueInit(&queue);
	if (root)
		QueuePush(&queue, root);
	while (top(&queue))
	{
		BiTreeNode* front = top(&queue);
		QueuePop(&queue);
		QueuePush(&queue, front->left);
		QueuePush(&queue, front->right);
	}
	return QueueEmpty(&queue);

}

首先我们需要了解完全二叉树的性质,他和满二叉树类似,但是序号必须和满二叉树相同,这时候我们采用层序遍历的方式进行判断,我们将非空根节点入队,判断条件是队头元素不是空,每个节点入队当我们遇到空节点时我们判断队是不是都是空节点,如果是就是完全二叉树,为什么这样可以呢?当我们入队后一旦想出某一层时这一层的全部节点就会入队,然后进行判断就可以了。

2.12二叉树内存释放

二叉树内存前序中序后序都可以实现,但是我们如何做才能让这个操作根号的实现呢?我们想类似于前中后序遍历的样子进行,这时候你会发现,利用前序和中序遍历会提前将节点释放,以至于我们不能找到其他的节点,但是我们采用后序遍历就完美的避免了这个问题,所以我们在释放二叉树时我们经常采用后序遍历的方式。

void BTNodeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	BTNodeDestory(root->left);
	BTNodeDestory(root->right);
	free(root);
}

2.13树的创建

BiTree* BiTreeCreate(BiTree* bt)
{
	bt = (BiTree*)malloc(sizeof(BiTree));
	char ch;
	scanf("%c", &ch);
	if (ch != '#')
	{
		bt->data = ch;
		bt->lchild = BiTreeCreate(bt);
		bt->rchild = BiTreeCreate(bt);
	}
	else
		bt = NULL;
	return bt;
}

3.二叉树的性质

1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有 个结点.
2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是 .
3. 对任何一棵二叉树, 如果度为0其叶结点个数为 , 度为2的分支结点个数为 ,则有 = +1
4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h= . (ps: 是log以2
为底,n+1为对数)
5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对
于序号为i的结点有:
1. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
2. 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
3. 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

4.总结

        事实上我们二叉树的内容并不是很难,更多的需要我们去理解,这就需要我们多去感受一线二叉树的实现,最后希望大家可以来三连。到这里我们树的内容就解决了三分之二,其余的三分之一我会将以C++的形式来为大家讲解,不过可能会等上一段时间了。在下一篇文章中我会给大家带来一些二叉树的题目,欢迎大家持续关注。

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

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

相关文章

ahk系列-windows超级运行框-表达式计算(12)—功能汇总

1、环境准备 windows 7&#xff0c;8&#xff0c;10&#xff0c;11操作系统ahk 2.x_64位翻译功能需要联网使用 2、使用方式 输入winR打开windows运行框 get/getpath 命令获取配置文件环境变量set/sets 设置 “用户/系统” 环境变量或者pathencode/decode 中文编码和解码len…

Python3+RIDE+RobotFramework自动化测试框架搭建过程详解

一、Python安装 最新版Python下载地址&#xff1a;https://www.python.org/ 根据操作系统选择对应版本制品下载安装即可&#xff0c;本机用的是Windows x86-64 executable installer。 注意事项&#xff1a; 安装完成后检查下环境变量&#xff0c;默认会配置好&#xff0c;可…

路径规划之PRM算法

系列文章目录 路径规划之Dijkstra算法 路径规划之Best-First Search算法 路径规划之A *算法 路径规划之D *算法 路径规划之PRM算法 路径规划之PRM算法 系列文章目录前言一、前期准备1.栅格地图2.采样3.路标 二、PRM算法1.起源2.流程3. 优缺点4. 实际效果 前言 之前提到的几种…

Recyclerview属性配置记录

Recyclerview属性&#xff1a; 1、requiresFadingEdge&#xff1a;属性用来设置拉滚动条时 &#xff0c;边框渐变的方向。 none&#xff08;边框颜色不变&#xff09;horizontal&#xff08;水平方向颜色变淡&#xff09;vertical&#xff08;垂直方向颜色变淡&#xff09; …

ConcurrentHashMap实现线程安全原理

我们知道&#xff0c;在日常开发中使用的HashMap是线程不安全的&#xff0c;而线程安全类HashTable只是简单的在方法上加锁实现线程安全&#xff0c;效率低下&#xff0c;所以在线程安全的环境下我们通常会使用ConcurrentHashMap。 1. 初始化数据结构时的线程安全 HashMap的底…

代码随想录算法训练营第四十二天 _ 动态规划_01背包问题、416.分割等和子集。

学习目标&#xff1a; 动态规划五部曲&#xff1a; ① 确定dp[i]的含义 ② 求递推公式 ③ dp数组如何初始化 ④ 确定遍历顺序 ⑤ 打印递归数组 ---- 调试 引用自代码随想录&#xff01; 60天训练营打卡计划&#xff01; 学习内容&#xff1a; 二维数组处理01背包问题 听起来…

如何本地搭建Linux DataEase数据可视化分析工具并实现公网访问

文章目录 前言1. 安装DataEase2. 本地访问测试3. 安装 cpolar内网穿透软件4. 配置DataEase公网访问地址5. 公网远程访问Data Ease6. 固定Data Ease公网地址 前言 DataEase 是开源的数据可视化分析工具&#xff0c;帮助用户快速分析数据并洞察业务趋势&#xff0c;从而实现业务…

虚拟机网络设置

虚拟机网络设置 上一篇讲了虚拟机的安装与使用 因为虚拟机默认使用的是网络地址转换和端口转发的方式&#xff0c;这种方式对于后面的开发不方便&#xff0c;所以我们需要设置虚拟机网络。 直接修改虚拟机的网卡信息 进入虚拟机并和虚拟机建立连接&#xff0c;在虚拟机内修改…

SFX的妙用——如何在不安装软件的情况下打开自定义格式文件?

前段时间看到群友讨论压缩包能不能运行&#xff0c;想起了n年前用自解压文件SFX实现的一个“需求”&#xff1a;在没有安装任何应用软件的Windows&#xff08;当时还要支持XP&#xff09;上能双击打开自定义格式的文件。当时第一反应是这“需求”太奇葩了&#xff0c;简直是不可…

一对多聊天

服务端 import java.io.*; import java.net.*; import java.util.ArrayList; public class Server{public static ServerSocket server_socket;public static ArrayList<Socket> socketListnew ArrayList<Socket>(); public static void main(String []args){try{…

两种做法——判断是否是二叉搜索树

https://leetcode.cn/problems/validate-binary-search-tree/description/?envTypestudy-plan-v2&envIdtop-interview-150 方法一&#xff1a;中序遍历 考虑只有两个节点和一个结点的情况&#xff0c;可以头尾各加一个最大最小值&#xff0c;不用特判了&#xff0c;也可…

流量分析1--菜刀666

1&#xff1a;菜刀666&#xff1a; 题目描述 分析流量包&#xff0c;过滤http数据流 追踪TCP数据流 对比第5个流和第7个流发现&#xff0c;同样的目录下 多出了6666.jpg。猜测是由攻击者上传&#xff0c;直接在请求包里搜索FFD8--FFD9 保存为1.jpg 利用foremost工具对1.jpg进…

Vis.js教程(四):给关系图的节点设置Image背景

1、引言 在Vis.js教程三中我们介绍了如何给关系图设置关系指向以及关系标签。 本节我们计划给关系图节点设置背景&#xff0c;拿菲尼克斯太阳队关系图的例子来说&#xff0c;如果给每一个球员节点都加上图片&#xff0c;这样看起来远远比名称更直观。 2、添加节点背景图片 …

phpStudy本地快速搭建网站,实现无公网IP固定地址远程访问

文章目录 [toc]使用工具1. 本地搭建web网站1.1 下载phpstudy后解压并安装1.2 打开默认站点&#xff0c;测试1.3 下载静态演示站点1.4 打开站点根目录1.5 复制演示站点到站网根目录1.6 在浏览器中&#xff0c;查看演示效果。 2. 将本地web网站发布到公网2.1 安装cpolar内网穿透2…

【无线网络技术】——无线局域网(学习笔记)

&#x1f4d6; 前言&#xff1a;本章首先介绍无线局域网的基本概念&#xff0c;然后详细介绍IEEE 802.11的基本工作原理&#xff0c;侧重于媒体访问控制和一跳范围内的通信技术。 目录 &#x1f552; 1. 概述&#x1f558; 1.1 覆盖范围&#x1f558; 1.2 特点&#x1f558; 1.…

设计新手利器!10款Windows免费设计软件推荐

1.即时设计 即时设计是国内首款协作式 UI 设计工具&#xff0c;更是同类产品中首先实现百万用户的设计软件。作为国产软件&#xff0c;即时设计的全中文操作系统和多设备平台的使用支持让它更加符合国内设计师的使用习惯。同时&#xff0c;即时设计也为用户提供了强大的功能支…

HarmonyOS开发(十):通知和提醒

1、通知概述 1.1、简介 应用可以通过通知接口发送通知消息&#xff0c;终端用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应用。 通知使用的的常见场景&#xff1a; 显示接收到的短消息、即使消息...显示应用推送消息显示当前正在进行的事件&#xff0c…

Apache+mod_jk模块代理Tomcat容器

一、背景介绍 最近在看Tomcat运行架构原理, 正好遇到了AJP协议(Apache JServ Protocol). 顺道来研究下这个AJP协议和具体使用方法. 百度百科是这么描述AJP协议的: AJP&#xff08;Apache JServ Protocol&#xff09;是定向包协议。因为性能原因&#xff0c;使用二进制格式来传输…

剧本杀小程序搭建:打造线上剧本杀新体验

剧本杀是一款以角色扮演为主的游戏&#xff0c;一度成为了年轻人的最喜爱的社交游戏。在剧本杀市场需求下&#xff0c;剧本杀规模也迅速上升。今年第一季度&#xff0c;剧本杀市场规模环比增长47%&#xff0c;市场整体消费水平逐渐呈上升趋势。 随着剧本杀的不断发展&#xff…

通用plantuml 时序图(Sequence Diagram)模板头

通用plantuml文件 startuml participant Admin order 0 #87CEFA // 参与者、顺序、颜色 participant Student order 1 #87CEFA participant Teacher order 2 #87CEFA participant TestPlayer order 3 #87CEFA participant Class order 4 #87CEFA participant Subject order …