【初阶数据结构】详解二叉树 - 树和二叉树(三)(递归的魅力时刻)

文章目录

  • 前言
  • 1. 二叉树链式结构的意义
  • 2. 手搓一棵二叉树
  • 3. 二叉树的遍历(重要)
    • 3.1 遍历的规则
    • 3.2 先序遍历
    • 3.3 中序遍历
    • 3.4 后序遍历
    • 3.5 遍历的代码实现
      • 3.5.1 先序遍历代码实现
      • 3.5.2 中序遍历代码实现
      • 3.5.3 后序遍历代码实现
  • 4. 统计二叉树结点的个数
  • 5. 统计二叉树的高度
  • 6. 统计二叉树的指定层数的结点个数

前言

如果有看过的堆和堆排序这篇文章的话,你一定对二叉树的顺序存储有了一定的了解,但是这个是有特定的使用环境的。

那么在本文中,我将要给大家讲解二叉树的另一种表示方式——链式结构,以及我会给大家讲解有了顺序存储结构,为什么还要使用链式存储结构?以及如何用链式创建一棵二叉树?此外,还要讲解递归在二叉树中扮演着何种角色?

哈哈哈

1. 二叉树链式结构的意义

在学习堆时,我们说堆的本质就是一棵完全二叉树,而完全二叉树的结构注定了我们使用顺序表来存储比较方便,而这个就是二叉树的顺序存储。
二叉树的顺序存储
可能大家也意识到了一个点:好像二叉树的顺序存储有个要求,那就是这棵二叉树必须得是完全二叉树。没错!

如果我们不分青红皂白地使用顺序结构来存储二叉树会发生什么可怕的是事情呢?
请大家将目光往下注视:
非二叉树的顺序存储
可以看到,如果我们遇到的是一棵非完全二叉树,并且我们还要有顺序结构来存储这棵树。第一步,我们就得在逻辑上将这颗树补全为完全二叉树,但是补的地方我们是不能进行任何的操作的。那这个就十分尴尬,自己创建的空间却不能愉快地使用,有点扯淡了!而且这样的方式很浪费空间资源,从上图你就可以看出有几个空间是没有办法使用的。

那该怎么办呢?此时,天空一声巨响,二叉树的链式结构就闪亮登场了!

二叉树的链式结构针对的群体就是普通的二叉树。 那至于普通二叉树链式是如何被我们用代码创建的,让我们接着往下看!

2. 手搓一棵二叉树

这里为了降低大家的学习成本,我先不教大家如何用函数创建二叉树,如果大家对自己的二叉树比较有自信的话,可以移步到本文的后面,学习如何用函数创建一棵二叉树。

学习是要一步一步来的,我们不能不懂装懂,有时候也得直面不完美的自己!

二叉树链式结构示意图:
二叉链表

那我们这里开始就开始手搓一棵二叉树,为了方便大家学习,我会按照下面的图的给大家建立,往后的操作都是以这副图为基础。
图例
代码如下:

//二叉树结点的结构体
typedef int BTDataType;typedef struct BTNode
{BTDataType data;struct BTNode* left;struct BTNode* right;}BTNode;BTNode* BuyNewnode(BTDataType x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));newnode->data = x;newnode->left = NULL;newnode->right = NULL;return newnode;
}BTNode* CreateTree()
{BTNode* node1 = BuyNewnode(1);BTNode* node2 = BuyNewnode(2);BTNode* node3 = BuyNewnode(3);BTNode* node4 = BuyNewnode(4);BTNode* node5 = BuyNewnode(5);BTNode* node6 = BuyNewnode(6);//开始结点之间的链接node1->left = node2;node1->right = node3;node2->left = node4;node2->right = node5;node3->right = node6;return node1;
}

这种方式初学者来说十分的友好。


3. 二叉树的遍历(重要)

接下来,我来讲一下本文的精华 —— “二叉树的遍历”。为什么会说是精华的部分呢?因为想要学会这个就得先知道递归的规则,并且这是科班同学在练习中会经常遇到的题目。同时这个也是二叉树的入门门槛!

二叉树遍历有四种方式,分别是:

  • 先序遍历(可能有的书籍会称其为"先根遍历")
  • 中序遍历
  • 后序遍历
  • 层序遍历

3.1 遍历的规则

  1. 先序遍历:遍历顺序为根、左子树、右子树。记忆的规则就是,先序又称先根,顾名思义就是根结点先遍历。
  2. 中序遍历:遍历顺序为左子树、根、右子树。记忆的规则就是,中序是将根结点放在遍历的中间顺序。
  3. 后序遍历:遍历顺序为左子树、右子树、根。记忆的规则就是,后序是将根节点但在遍历的最后顺序。
  4. 层序遍历:遍历的顺序时按照一层层开始,每一层从左往右依次遍历各节点。

在本文,会重点讲解先序遍历、中序遍历以及后序遍历。

为了更好的讲解每种遍历的规则,接下来我会分篇幅给大家做进一步的讲解。

3.2 先序遍历

先序遍历:遍历顺序为根、左子树、右子树

任何一颗树都是由根节点及其子树所构成的。二叉树也是如此,二叉树由其根节点、左子树和右子树所构成。其中,左子树由其根节点、左子树和右子树所构成…。给人一种循环的感觉,而这个就是递归!大家可以从下图(只做了部分的划分)感受一下
树的剖析图
好了,我们根据先序遍历的规则,写出它的数据遍历的顺序(注意:空树用NULL表示)。

先序遍历的顺序:1 2 4 NULL NULL 5 NULL NULL 3 NULL 6 NULL NULL

怎么样,不是很困难吧。

3.3 中序遍历

中序遍历:遍历顺序为左子树、根、右子树

趁热打铁,我们把中序遍历也讲了。

有了先序遍历的经验,中序遍历洒洒水啦!

树的剖析图

这里我就直接写答案了:

中序遍历的顺序:NULL 4 NULL 2 NULL 5 NULL 1 NULL 3 NULL 6 NULL

3.4 后序遍历

后序遍历:遍历顺序为左子树、右子树、根

树的剖析图

后序遍历的顺序:NULL NULL 4 NULL NULL 5 2 NULL NULL NULL 6 3 1

3.5 遍历的代码实现

这个就体现出递归的魅力时刻了!

这里我会拿先序遍历作为重点讲解,其余遍历方式的思维都是一样的。

3.5.1 先序遍历代码实现

先序遍历:遍历顺序为根、左子树、右子树

//先序遍历
void PreOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}printf("%d ",root->data);PreOrder(root->left);PreOrder(root->right);
}

当遇到一个递归却被深深绕进去时,最好画一个递归展开图!

递归展开图

3.5.2 中序遍历代码实现

中序遍历:遍历顺序为左子树、根、右子树

//中序遍历
void InOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}InOrder(root->left);printf("%d ",root->data);InOrder(root->right);
}

3.5.3 后序遍历代码实现

后序遍历:遍历顺序为左子树、右子树、根

//后序遍历
void PostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}

结果展示
可能大家在平常的练习中看到的是这种形式的,
结果
要想出来这个效果,我们只需要把printf("NULL ")这个语句注释掉即可。但是需要提醒大家的一点就是,上面这幅图的结果并不是二叉树原本的模样,大家要理解本质!

哈哈


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

在这里我要给大家将一个非常重要的思想 —— “分治思想”

给大家设置一个场景,假如现在我是一位大学的校长,我要统计学校的人数。我该怎么做?

第一种方法:我到学生宿舍一个一个人的统计人数,每当宿舍有一个新生时,我就在我的小本本上画"正"字的一个笔画。最后我只要统计小本本上有多少个正字即可。

但是这个方法非常的费"校长"。不经的会感叹到这个校长当得也太累了吧!

第二种方法:既然身为一校之长,我肯定有一定的权力。我就让每个院的院长汇报各自院的人数给我,我再统计不就好了。院长接到任务后,就命令每个专业的系主任汇报各专业人数给我。每个系主任又叫每个班的班长统计各班的人数给他。之后,以宿舍为单位,让宿舍长汇报宿舍人数给班长,班长再做汇总,将结果给系主任。
这不就纯纯是打工人体系!!!

分治思想的体现
汇报人数的情况:
统计
有了这个思想之后,我们写代码!

int TreeSize(BTNode* root)
{//写法一if(root == NULL){return 0;}return TreeSize(root->left) + TreeSize(root->right) + 1;/* //写法二return root == NULL? 0: TreeSize(root->left) + TreeSize(root->right) + 1;*/
}

结果


5. 统计二叉树的高度

用了分治思想,这个代码似乎也能理解了。

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

结果


6. 统计二叉树的指定层数的结点个数

这里给大家提供一个思路:当前K层结点的个数 = 对应左子树K-1层结点的个数 + 对应右子树K-1层结点的个数

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

好了,本文就到这里结束了!

本文主要讲解了二叉树链式结构的定义以及接口的实现,其中有个重要的思想可以帮助我们更快的理解递归背后的本质,体会到递归的魅力。

最后如果觉得本文写的不错的话,麻烦给偶点个赞吧!!!

请添加图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【iOS】MVC架构模式

文章目录 前言MVC架构模式基本概念通信方式简单应用 总结 前言 “MVC”,即Model(模型),View(视图),Controller(控制器),MVC模式是架构模式的一种。 关于“架构模式”&a…

828华为云征文|华为云Flexus X实例docker部署最新Appsmith社区版,搭建自己的低代码平台

828华为云征文|华为云Flexus X实例docker部署最新Appsmith社区版,搭建自己的低代码平台 华为云最近正在举办828 B2B企业节,Flexus X实例的促销力度非常大,特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Ng…

Apache Hudi现代数据湖核心技术概论

1. 什么是 Apache Hudi 1.1 简介 Apache Hudi (Hadoop Upserts Deletes and Incrementals) 是一个开源的数据湖框架,旨在提供高效的数据管理和数据更新功能。它允许在大数据平台上执行诸如数据插入、更新和删除操作,同时支持增量式数据处理。Hudi 最初…

C++之STL—vector容器基础篇

头文件 #include <vector> //vector容器 #include <algorithm> //算法 基本用法&&概念 vector<int> v; v.push_back(10); vector<int >::iterator v.begin(); v.end(); 三种遍历方式 #include <vector> #include <algorithm>…

C++基础知识7 list

list 1. list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator的使用1.2.3 list capacity1.2.4 list element access1.2.5 list modifiers1.2.6 list的迭代器失效 2.1 模拟实现list 1. list的介绍及使用 1.1 list的介绍 1.2 list的使用 1.2.1 l…

51.字符串比较实例-用户登录

//已知正确的用户名和密码&#xff0c;请用程序实现模拟用户登录 //总共三次机会&#xff0c;登录之后给出相应的提示 import java.util.Scanner;public class 登录 {public static void main(String[] args) {//1.定义两个变量&#xff0c;记录正确的用户名和密码String righ…

操作系统迁移(CentOs -> Ubuntu)

目录 1. CentOs操作系统:备份数据 1.1 gitee备份 1.1.1 CentOs安装git 1.1.1.1 运行安装命令 1.1.1.2 运行安装命令时出错 1.1.1.3 再次执行安装命令 1.1.2 gitee创建仓库 1.1.2.1 创建仓库 1.1.3 备份 1.1.3.1 复制链接 1.1.3.2 克隆仓库 1.1.3.3 备份 1.3.3.4 查…

uniapp小程序持续获取用户位置信息,后台位置获取

做一个小程序持续获取用户位置信息的功能&#xff0c;即使小程序切换到后台也能继续获取&#xff0c;getLocation这个api只有小程序在前台才能获取位置&#xff0c;所以不用这个 先申请一个腾讯地图key 在uniapp项目配置源码视图里加上这个代码 先获取权限&#xff0c;再开启…

ERNIESpeed-128K在线智能聊天机器人项目(附源码)

本项目是基于百度千帆的智能聊天模型ERNIESpeed-128K开发的 一、技术栈 后端&#xff1a;java8springboot2.6.13 数据库&#xff1a;MongoDB 前端&#xff1a;vue2element-uimarked&#xff08;md格式&#xff09; 二、MongoDB与对话存储的设计 使用MongoDB来储存对话&am…

【Linux】常用指令(下)(内含more、less、 head、tail、date、find、grep、zip、tar以及学习笔记)

文章目录 前言1. more指令2. less指令&#xff08;重要&#xff09;3. head指令4. tail指令5. 管道&#xff08;做到学会使用即可&#xff09;6. date指令6.1 时间戳 7. cal指令8. find指令9. grep指令10. zip/unzip指令11. tar指令 前言 Linux下的常用指令终于要在本文落下帷…

kitti2bag原始数据转为bag包工具使用、SLAM精度评估工具evo安装及使用、KITTI原始数据集对应关系

最近在学习SLAM&#xff0c;需要使用到精度评估工具evo&#xff0c;写下这篇笔记记录自己暂时使用到的命令&#xff0c;在此只做一个记录&#xff0c;后续学习过程中需要使用新命令会逐渐追加上去。 目录 evo的安装 evo的使用 Kitti序列00-10对应关系 kitti2bag工具包安装…

docker部署Stirling-PDF

github网址&#xff1a; GitHub - Stirling-Tools/Stirling-PDF: #1 Locally hosted web application that allows you to perform various operations on PDF files 1、官方docker镜像无法拉取&#xff0c;使用别人阿里云私人镜像仓库下载Stirling-PDF镜像&#xff1a; dock…

Maven-四、继承

Maven进阶 文章目录 Maven进阶前言继承设置继承依赖管理总结 前言 一个项目中的不同模块可能引用的是同一个依赖&#xff0c;在这种情况下&#xff0c;单独在某个模块内引用太麻烦&#xff0c;于是maven使用继承的思想&#xff0c;在父模块中配置依赖包&#xff0c;其他需要这…

IDEA连接数据库报错:Access denied for user ****

使用IDEA开发时&#xff0c;通过Databse连接数据库。多次连接报错&#xff1a;Access denied for user **** 如下所示&#xff1a; ​ ‍ ‍ ​ ‍ 花了不少时间排查&#xff0c;确认账号、密码&#xff0c;后面发现账号后多了个空格&#xff0c;而且不容易发现&#xf…

Excel的基本应用 ___2

快速插入函数 方法一&#xff1a; 方法二&#xff1a;快捷键 Alt&#xff1a;求和 动态查看 利用函数清单选择函数 相对地址和绝对地址的转换 FnF4

828 华为云征文|华为 Flexus 云服务器搭建萤火商城 2.0

在今天这个意义非凡的日子&#xff0c;我怀揣着满心的期待与憧憬&#xff0c;毅然踏上了利用华为 Flexus 云服务器搭建轻量级、高性能、前后端分离的电商系统萤火商城 2.0 的征程。这一旅程&#xff0c;注定充满了挑战与惊喜&#xff0c;犹如在浩瀚的数字海洋中探索未知的宝藏。…

基于Python flask的医院管理学院,医生能够增加/删除/修改/删除病人的数据信息,有可视化分析

研究背景 随着信息技术的飞速发展&#xff0c;医疗行业逐渐进入了数字化管理的时代。传统的医院管理方式通常依赖于手动记录和纸质文件&#xff0c;不仅工作量巨大&#xff0c;而且容易导致数据的丢失或错误&#xff0c;无法及时、准确地反映病人的健康状况和医院的运营效率。…

Maven-六、私服仓库

Maven 文章目录 Maven前言下载到本地解压启动并访问资源管理maven配置创建仓库选择使用仓库配置私服地址 资源上传配置资源上传操作私服连接中央仓库总结 前言 模块在引用依赖时一般先看本地仓库再看中央仓库&#xff0c;但是在团队开发中&#xff0c;不同人员要引用一些项目通…

《深度学习》—— 神经网络中常用的激活函数

文章目录 1. Sigmoid 激活函数2. Softmax 激活函数3. ReLU 激活函数4. Leaky ReLU 激活函数5. ELU 激活函数6. Tanh 激活函数 激活函数&#xff08;Activation Function&#xff09;是在人工神经网络的神经元上运行的函数&#xff0c;负责将神经元的输入映射到输出端。它在神经…

Django学习实战篇四(适合略有基础的新手小白学习)(从0开发项目)

前言&#xff1a; 在本章中&#xff0c;我们开始编写面向用户的界面&#xff0c;其中只涉及简单的HTML结构&#xff0c;不会做太多美化&#xff0c;目的就是把后台创建的数据展示到前台。 从技术上来讲&#xff0c;这一节将涉及Django 中function view和 class-based view 的用…