数据结构之二叉树详解[1]

在前面我们介绍了堆和二叉树的基本概念后,本篇文章将带领大家深入学习链式二叉树。

1.预备知识

2.二叉树结点的创建

3.二叉树的遍历 

3.1前序遍历

3.2中序遍历

3.3 后序遍历

4.统计二叉树的结点个数

5.二叉树叶子结点的个数

 6.二叉树第k层的结点个数

 7.总结


1.预备知识

由于二叉树的性质,我们在实现二叉树及其相关功能时会经常使用到递归的操作。

所以我们首先介绍一下递归算法。

在百度百科中,对于递归算法的定义是:某个函数直接或者间接地调用自身,这样原问题的求解就转换为了许多性质相同但是规模更小的子问题。

很多同学或许对这句话无法理解,没有关系。

在这里我们仅仅将其当作一个工具,在编写代码时,我们只需搞清楚繁杂的递归调用中的一次调用即可,不需要去深究他调用的过程。在文章后续的代码实现中,大家可以深刻体会到这句话的意思。

2.二叉树结点的创建

 既然是链式二叉树,对学习过链表的大家就很简单了。直接上代码

typedef char BTDataType;

typedef struct BTreeNode//每一个结点的结构
{
	BTreeNode* left;//指向左树
	BTreeNode* right; //指向右树
	BTDataType data;//结点的值
}BTNode;


BTNode* BuyNode(BTDataType x)//为新结点开辟空间
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	newnode->data = x;
	newnode->left = newnode->right = NULL;
	return newnode;
}

3.二叉树的遍历 

二叉树的遍历有四种:前序遍历、中序遍历、后序遍历、层序遍历。

今天我们在这里讲解前三种遍历,层序遍历请看下回分解。

3.1前序遍历

前序遍历就是先遍历根结点,在遍历左子树,最后遍历右子树。

理解了概念我们直接上代码。

void PreOrder(BTNode* root)//前序 根 左子树 右子树
{
	if (root == NULL)
	{
		printf("NULL");
		return;
	}
	else {
		printf("%c", root->data);//打印根节点
		PreOrder(root->left);//递归遍历左子树
		PreOrder(root->right);//递归遍历右子树
	}
}

这里我们就使用到了递归。该如何理解呢。

我们只关注一次调用,既然遍历左树,

那么我们就让根去找,即 PreOrder(root->left)。

遍历右树,即PreOrder(root->right)。

中间是如何进行调用的细节我们不需要深究,我们只需要知道这个递归的写法。剩下的交给计算机。如果大家仍没理解,可以画个对照代码画一个草图。

 

3.2中序遍历

中序遍历:先遍历左子树,在找根,最后遍历右子树。

代码如下

void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL");
		return;
	}
	else {
		
		InOrder(root->left);//遍历左树
		printf("%c", root->data);//找根
		InOrder(root->right);//遍历右树
	}
}

这里的递归我们仍然按一样的方法进行理解,只看一层调用。大家可以看图理解。 

3.3 后序遍历

后序遍历:先遍历左子树,再遍历右子树,最后找根。

void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL");
		return;
	}
	else {

		PostOrder(root->left);//遍历左树
		PostOrder(root->right);//遍历右树
		printf("%c", root->data);//找根
	}
}

后序的图大家就自己画画吧。 

4.统计二叉树的结点个数

 如何统计二叉树的结点个数呢。

思路很简单,没遍历一个非空结点,个数加一。我们看下面代码。

void TreeSize(BTNode* root)
{
	if (root == NULL)
		return;
	int count = 0;
	count++;//既然不为空,那么一定就有一个结点的存在
	TreeSize(root->left);
	TreeSize(root->right);
}

如果大家觉得这个代码对的话,那就掉入陷阱了!

在递归调用中,count存在于栈帧之中,并且递归的每一次调用都会开辟新的一块栈帧,这样的话我们的count就无法进行值的保存而达到连续的效果。所以这里我们不能这样进行实现。

下面我们介绍正确的写法。

void TreeSize(BTNode* root,int*p)//p为指向节点个数的指针
{
	if (root == NULL)
		return;
	++(*p);//结点个数++,既然不为空,那么一定有一个根结点,所以先++
	TreeSize(root->left, p);//遍历左子树的结点
	TreeSize(root->right, p);//遍历右子树的结点
}

我们在这里运用定义了一个外部指针变量,用来记录结点的个数,传入的是记录结点个数变量的地址。这样就可以避免 原来出现的问题了。

 其实这里还有个更加简单的方法,直接用root来记录结点个数。

int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

5.二叉树叶子结点的个数

 既然可以得到结点总数,那叶子结点是不是也可以得到呢。我们先上代码再解释。

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);//找叶子结点
}

既然要找叶子结点首先我们要知道叶子结点的性质:左右子树均为空。

所以我们在递归的时候需要加入叶子结点的判断条件,如果是叶子结点就要返回。

当然在进行递归前要判断根节点是否存在或者根结点是否有值,我们将其划分为代码中的一中情况。

 6.二叉树第k层的结点个数

我们该如何求任意一层的结点个数呢。

我们将求第k层的结点个数转化为求第k-1层结点的左右子树个树是不是就和我们求叶子结点个数大同小异了呢!

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

我们加入需要的层数k,我们从根结点往下找第k层,如果要使其找到k层,就要使k=1。我们画图理解 。

我们假设要求第三层的结点个数,k=3。根结点为第一层,与其匹配的k=3,所以到找到第三层,就要使k--,简而言之,我们要找到的那一层匹配的k=1。这里可能有点绕,大家可以试着自己画图理解 。

 7.总结

 二叉树的内容到这里并没有结束,后序的内容需要用到队列的知识,所以我会在穿插队列的实现后继续为大家讲解二叉树的相关知识!敬请期待!

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

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

相关文章

如何使用恢复模式修复Mac启动问题?这里提供详细步骤

如果你的Mac无法启动,不要惊慌,Mac有一个隐藏的恢复模式,你可以使用它来诊断和修复任何问题,或者在需要时完全重新安装macOS。以下是如何使用它。 如何在Mac上启动到恢复模式 你需要做的第一件事是启动到恢复模式。尽管操作说明会因你使用的Mac电脑而异,但幸运的是,启动…

[数据结构1.0]快速排序

最近学习了快速排序,鼠鼠俺来做笔记了! 本篇博客用排升序为例介绍快速排序! 1.快速排序 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值&#x…

(四)Spring教程——控制反转或依赖注入与Java的反射技术

IoC的底层实现技术是反射技术,目前Java、C#、PHP 等语言均支持反射技术。 在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法;对任意一个对象,都能够调用它的任意方法和属性(包括私有的方法…

【数据可视化01】matplotlib实例3之数据统计

目录 一、引言二、实例介绍1.百分位数为横条形图2.箱线图定制化3.带有自定义填充颜色的箱线图4.箱线图5.箱线图和小提琴图6.二维数据集的置信椭圆 一、引言 matplotlib库 可以用来创建各种静态、动态、交互式的图形,并广泛应用于数据分析和数据可视化领域。 二、实…

6. 第K小的和-二分

6.第K小的和 - 蓝桥云课 (lanqiao.cn) #include <bits/stdc.h> #define int long long #define endl \n using namespace std; int n,m,k,an[100005],bm[100005]; int check(int x){int res0;//序列C中<x的数的个数for(int i0;i<n;i){//遍历数组A&#xff0c;对于每…

【Linux】如何在Linux中配置自己的环境变量?

文章目录 配置环境变量方法一&#xff1a;【>>】使用追加重定向方法二&#xff1a;使用【export PATH$PATH:/路径】(推荐) 配置环境变量 那要怎么去将一个系统路径添加到【环境变量】中呢 方法一&#xff1a;【>>】使用追加重定向 &#x1f6a9;这里一定要主要覆盖…

mongodb备份还原指南

MongoDB 提供的命令行实用程序mongodump和mongorestore创建备份和恢复数据的过程。 一、数据备份 mongorestore和mongodump实用程序可处理BSON数据转储&#xff0c;对于创建小型部署的备份非常有用。要实现弹性且无中断的备份&#xff0c;请将文件系统快照或区块级磁盘快照与…

Git 的原理与使用(中)

Git 的原理与使用&#xff08;上&#xff09;中介绍了Git初识&#xff0c;Git的安装与初始化以及工作区、暂存区、版本库相关的概念与操作&#xff0c;本文接着上篇的内容&#xff0c;继续深入介绍Git在的分支管理与远程操作方面的应用。 目录 五、分支管理 1.理解分支 2.创…

免费Premiere模板,几何图形元素动画视频幻灯片模板素材下载

Premiere Pro模板&#xff0c;几何图形元素动画视频幻灯片模板 &#xff0c;组织良好&#xff0c;易于自定义。包括PDF教程。 项目特点&#xff1a; 使用Adobe Premiere Pro 2021及以上版本。 19201080全高清。 不需要插件。 包括帮助视频。 免费下载&#xff1a;https://prmu…

Java毕业设计 基于SpringBoot vue药店管理系统

Java毕业设计 基于SpringBoot vue药店管理系统 SpringBoot 药店管理系统 功能介绍 员工 登录 个人中心 修改密码 个人信息 查看供应商信息 查看药品 查看进货 查看销售 管理员 登录 个人中心 修改密码 个人信息 供应商类型管理 供应商信用等级类型管理 药品类型管理 供应商信…

【Web后端】MVC模式

1、简介 MVC模式&#xff0c;全称Model-View-Controller&#xff08;模型-视图-控制器&#xff09;模式&#xff0c;是一种软件设计典范&#xff0c;它将应用程序的用户界面&#xff08;视图&#xff09;和业务逻辑&#xff08;模型&#xff09;分离&#xff0c;同时提供了一个…

langchain_community FAISS保存与加载faiss index

参考: https://github.com/langchain-ai/langchain/issues/18285 https://api.python.langchain.com/en/latest/vectorstores/langchain_community.vectorstores.faiss.FAISS.html#langchain_community.vectorstores.faiss.FAISS 1、保存save_local import pandas as pd ##…

(深度估计学习)Win11复现DepthFM

目录 1. 系统配置2. 拉取代码&#xff0c;配置环境3.开始深度预测4.运行结果 论文链接&#xff1a;https://depthfm.github.io/ 讲解链接&#xff1a;https://www.php.cn/faq/734404.html 1. 系统配置 本人系统&#xff1a;Win11 CUDA12.2 python3.11.5 这里附上几个CUDA安装链…

iOS——runtime

什么是runtime 我们都知道&#xff0c;将源代码转换为可执行的程序&#xff0c;通常要经过三个步骤&#xff1a;编译、链接、运行。 C 语言 作为一门静态类语言&#xff0c;在编译阶段就已经确定了所有变量的数据类型&#xff0c;同时也确定好了要调用的函数&#xff0c;以及函…

算法提高之加成序列

算法提高之加成序列 核心思想&#xff1a;迭代加深 dfs 从上往下逐渐增大depth 这样下面没有用的方案就不用遍历了 #include <iostream>#include <cstring>#include <algorithm>using namespace std;const int N 110;int n;int path[N];//当前求哪个位置…

如何去掉图片背景改成透明的?一键图片去底色工具推荐

如何去掉图片背景改成透明的&#xff1f;在很多比较特殊的场景中&#xff0c;我们需要把图片背景底色去除后再进行使用&#xff0c;比如一些商品展示图或者是网页设计中的一些logo图标&#xff0c;专业人士会直接选择使用ps来处理&#xff0c;但是也有许多新手小白不知道怎么去…

steam商店打不开、steam商店错误代码-118的解决方法

现在steam已经开始了&#xff0c;有很多好玩的游戏都在这段时间相继打折&#xff0c;虽然游戏众多&#xff0c;但是不是所有人都能把这些游戏都买下来&#xff0c;有一些小伙伴喜欢的游戏苦于没有足够的资本去购买&#xff0c;steam会以各种名义举办特惠活动吸引玩家们&#xf…

如何实现微信扫码登录windows操作系统

将微信扫码登录功能集成到Windows操作系统级别的身份认证系统&#xff08;如你所提到的“安当ASP身份认证系统”&#xff09;是一个复杂的任务&#xff0c;因为Windows操作系统本身并不直接支持第三方应用&#xff08;如微信&#xff09;作为登录凭证。然而&#xff0c;你可以通…

Docker 部署 Nginx 实现一个极简的 负载均衡

背景: Nginx是异步框架的网页服务器&#xff0c;其常用作反向代理(负载均衡器)。在一般的小项目中, 服务器不多, 如果不考虑使用服务注册与发现, 使用Nginx 可以容易实现负载均衡。 在特此写一个快速入门 Nginx 的技术贴, 使用 Docker 部署 Nginx, 实现一个极简的加权轮询负载均…