树与二叉树的存储与遍历

文章目录

  • 一、树概念
  • 二、二叉树
  • 三、二叉树的存储与遍历


一、树概念

如前面的顺序表,链表,栈和队列都是线性的数据结构,树是非线性的结构。树可以有n个结点,n>=0,当n=0是就表示树为空
n>0,代表树不为空,不为空的树,它只有一个根结点,然后其余的结点又是构成互不相交的树,然后这些树本身又是一棵树,这些树且为根节点的子树。
任何一棵树都由两部分构成
1、根
2、子树
然后子树又由根和子树构成…无穷无尽的,直到为空为止,所以树又是递归定义的
在这里插入图片描述

根是唯一的但是它的子树有许多,莫得限制,且这些子树它们永远也不会相交。
树节点
树是由许多结点构成的,那么每个结点又是啥样的嘞?树的每个结点它有可能会有子树,且它拥有子树的数量也是它该节点的度,那么整棵树的度为多大?,一颗树的度为该树内部结点的度的最大值
在这里插入图片描述

上述这颗树的度也是结点B的度,为4,然后就像D,E,F,G,C,这些结点它后面没有子树了,也就是度为0的结点,这些结点也有另一个名字:叶子结点,然后嘞像B结点为非叶子结点。

节点关系
然后这些结点之间有什么关系?
这些结点它的子树的根也叫做它的孩子,然后这个结点也是它孩子结点的双亲

在这里插入图片描述
如结点A

蓝颜色圈起来的为它的子树,然后这些子树的根B,C又为A结点的孩子,然后嘞A也是它两个孩子结点的双亲结点,如A结点是B和C结点的双亲,B,C结点为A的孩子那么B,C它们两个结点之间又是什么关系?它们有同一个双亲,那么有同一个双亲在我们现实生活中难道不是兄弟吗,没错在树中有同一个双亲结点的孩子结点它们之间互为兄弟关系,称为兄弟结点。其实这些关系是借鉴生活中对应的家庭中的关系

树高度
树的高度也叫树的层次,树的根结点所在为第一层,然后它的孩子为第二层
在这里插入图片描述

这颗树高度为4,如果给定某个结点在第h层,那么它的孩子结点在第h+1层

树的存储
由于每个节点的孩子可以有很多个,根本不知道它的孩子节点有多少个,除非树中已经明确给出了树的度为n,那么就可以定义n个孩子节点
但是如果不知道度为多少,应该如何定义树?
有一种存储方式很适合树结构表示:左孩子又兄弟表示法

typedef int TDataType;
typedef struct BTNode
{
	struct BTNode* leftchild;//指向根节点的左孩子
	struct BTNode* rightbrother;//指向左孩子它的右兄弟
	TDataType data;
}BTNode;

这种方法好处是不管该节点有多少孩子节点,都只需要知道它的左孩子然后就可以找到它其他的孩子节点,不论怎样都只有两个指针
在这里插入图片描述
A的右兄弟为空然后A有两个孩子,但是他不会管他自己有多少孩子节点,它只需要找到它的左孩子,然后再通过它的左孩子就可以找到它的右孩子了。在这里插入图片描述

通过每一颗子树的根找到它的左孩子,然后再找左孩子的右兄弟,这个只有两个指针,感觉上像是二叉树,但是并不是,二叉树一个节点最多只有两个孩子,但是这里一个节点可以有多个孩子节点
不管有多少个孩子都只需要找第一个孩子,然后剩下的用兄弟指针去链接,每个节点都是两个指针,这点有些像二叉树,那么下面就引入二叉树

二、二叉树

二叉树就是树的度不大于2,也就是每个结点它的孩子结点不超过两个,每个结点的子树不超过两棵,然后在左边的那个结点为左孩子,右边的结点为右孩子。每一棵二叉树由根,左子树,右子树构成。二叉树也具有树的基本特性
在这里插入图片描述
在这里插入图片描述

左边的为左子树,右边的为右子树 二叉树可以为空,也可以只有一个节点(根),亦可以只有左子树或者只有右子树,还可以左子树和右子树都有

但是二叉树中有两个特殊的树

二叉树又有几种特殊的

  • 满二叉树
  • 完全二叉树

满二叉树叶子结点在同一层上且叶子结点只出现在最后一层,非叶子结点的度一定为2,就是每一层都是满的,那么高度为h的满二叉树有多少的节点?
在这里插入图片描述

每一层节点个数相加可以发现是一个等比数列,节点个数也就是等比数列求和为 2^h - 1

在这里插入图片描述
那么假设满二叉树有N个节点,求其高度h
在这里插入图片描述

由于log2(N-1)算出的结果很大程度上可能是小数,但是高度一般用整数表示,那么以得到的值向下取整得到整数然后再加一就为满二叉树的高度

还有就是同普通二叉树相比满二叉树的结点个数是最多的.
在这里插入图片描述

完全二叉树

如果二叉树有h层,那么它的前h-1层都是满的,最后一层不一定满但是要求最后一层从左到右是连续的
在这里插入图片描述

那么假设完全二叉树高度为h的节点数量的范围是多少?

N ~[log^(h-1)^,log^h^-1] 最少前h-1层是满的第h层只有一个节点,最多也就是一棵满二叉树

任意一棵二叉树
它的叶子结点数一定比度为2的结点数目多一个,即假设叶子结点数为n0,度为2的结点数为n2,那么n0=n2+1;

在这里插入图片描述

且完全二叉树中度为1的节点最多只有一个,或者就是没有度为1的节点,因为其是连续的,最多只会缺少右孩子

三、二叉树的存储与遍历

二叉树的存储
二叉树用数组存储容易会造成空间上的浪费,如果二叉树只有左子树或者右子树
在这里插入图片描述

绿色部分那片内存空间浪费了,没有被使用,因此用链式存储结构较为合适
但是如果是一棵完全二叉树的话,用顺序存储结构就较好了,因为完全二叉树是连续的

二叉树链式存储结构

typedef int TDataType;
typedef struct BTNode
{
	struct BTNode* left;
	struct BTNode* right;
	TDataType data;
}BTNode;

一个指针指向它的左孩子,一个指针指向右孩子

二叉树遍历
二叉树遍历方式主要有四种,但是我这里先分享三种遍历方式

  • 前序遍历
  • 中序遍历
  • 后序遍历

先手动构建二叉树的节点

BTree* BuyNode(TDataType x)
{
	BTree* newnode = (BTree*)malloc(sizeof(BTree));
	if (newnode == NULL)
	{
		perror("malloc fail\n");
		return NULL;
	}
	newnode->data = x;
	newnode->left = NULL;
	newnode->right = NULL;
	return newnode;
}

然后再自己创建一棵二叉树叭
在这里插入图片描述

BTree* BTCreat()
{
	BTree* newnode1 = BuyNode(1);
	BTree* newnode2 = BuyNode(2);
	BTree* newnode3 = BuyNode(3);
	BTree* newnode4 = BuyNode(4);
	BTree* newnode5 = BuyNode(5);
	BTree* newnode6 = BuyNode(6);
	newnode1->left = newnode2;
	newnode1->right = newnode3;

	newnode2->left = newnode4;
	newnode2->right = NULL;

	newnode3->left = newnode5;
	newnode3->right = newnode6;

	newnode5->left = NULL;
	newnode5->right = NULL;
	newnode6->left = NULL;
	newnode6->right = NULL;
	return newnode1;
}

前序遍历
前序遍历究竟是如何遍历二叉树的呢?
由于一棵二叉树由三部分构成:根、左子树、右子树
在这里插入图片描述

每一棵子树可以拆分为三部分,一直拆,直到子树为空就不可再拆分了

如果一棵二叉树是空,那么直接返回空,否则就是先访问这棵二叉树的根节点,然后再前序遍历它的左子树,它的左子树又是先访问它的根,然后又是左子树,当它的左子树以前序遍历访问直到空之后再以同样的前序遍历访问它的右子树,而它的右子树又是先遍历它的左子树依此直到为空,可以观察到访问是递归的,

前序遍历就是先访问其根,然后递归访问它的左子树,而左子树又由根,左子树,右子树,每一棵子树都由根,左子树,右子树构成,以前序遍历访问下去直到访问到空则返回然后访问它的右子树,右子树为空再返回,回溯了访问它双亲结点的右子树,最后回溯到整棵树的根,然后开始遍历访问整棵树的右子树,访问它的右子树时同样遵循先访问根,再访问左子树,最后访问右子树,遇到空则开始返回回溯
在这里插入图片描述
先访问 1,然后走它的左子树2,而它的左子树2又有根,左子树,右子树,访问2,然后再走它的左子树4,访问4,然后走4的左子树,4的左子树为空,代表4的左子树走完了,那么走它的右子树,它的右子树也为空,那么以4为子树作为2的左子树走完了,这回开始走2的右子树,2的右子树为空,那么就代表以2为子树作为1的左子树走完了,这回开始走1的右子树。
而1的右子树3不为空,又开始先访问3,然后走3的左子树5,访问5,然后走5的左子树,5的左子树走完了就代表以5为子树作为3的左子树走完了开始走3为子树它的右子树6不为空,访问6再走它的左子树,右子树最后就是全部都访问完了

这里前序我是将其空都算上的便于理解
前序 1 2 4 NULL NULL NULL 3 5 NULL NULL 6 NULL NULL
每一棵树都是由根,左子树,右子树构成

void PreOrder(BTree* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

前序遍历递归展开图
在这里插入图片描述
右子树也是一样的展开

中序和后序遍历的展开图这里就不再画了

中序遍历先访问左子树、再根、最后右子树

//中序遍历先访问每颗子树的左子树,直到左子树为空,才返回然后访问根,然后再访问以这个根为子树的右子树,右子树又访问其左子树,
//若干个子问题,一直拆,每棵树又由根,右子树,左子树三部分构成
//在中序遍历时要先访问每颗子树的左子树,直到以它为根的左子树为空,才访问它然后再访问其右子树

//每访问一次子树都是一次函数调用,且每一次函数调用都开辟一个函数栈帧用来维护这次函数栈帧开辟的空间,且每次返回时函数栈帧弹出,函数栈帧跳到调用它的
//那个函数以维护它的栈帧空间,且函数调用使用空间是允许重复的,即一次函数调用返回之后这块空间回收给操作系统然后下一次再调用其他函数
//又可以用这块内存空间
void InOrder(BTree* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}

中序 NULL 4 NULL 2 NULL 1 NULL 5 NULL 3 NULL 6 NULL

后序遍历先访问左子树、再右子树,最后访问根

//先访问根的左子树,然后再访问右子树最后访问根
// 左子树又拆分为根左子树右子树然后又先访问左子树,后右子树最后根
// 直到那颗子树左右子树都为空然后就访问它(根),然后回溯到它的双亲结点,以该双亲节点为根再访问它的右子树,
// 它的右子树又是先访问它的左子树,然后右子树最后根
// 最后直到根的左子树访问完了之后再访问右子树,最后再访问根
// 其实都是访问以每一颗子树为根的节点,只是时机不同
//
void PosOrder(BTree* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	PosOrder(root->left);
	PosOrder(root->right);
	printf("%d ", root->data);
}

后序 NULL NULL 4 NULL 2 NULL NULL 5 NULL NULL 6 3 1

今天的树与二叉树就基本概念分享到这里了,各位再见。

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

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

相关文章

Idea+maven+spring-cloud项目搭建系列--11 整合dubbo

前言: 微服务之间通信框架dubbo,使用netty (NIO 模型)完成RPC 接口调用; 1 dubbo 介绍: Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提…

如果大学能重来,我绝对能吊打90%的大学生,早知道这方法就好了

最近收到很多大学生粉丝的私信,大多数粉丝们都迷茫着大学计算机该怎么学,毕业后才能找到好工作。 可能是最近回答这方面的问题有点多,昨晚还真梦回大学…其实工作了20多年,当过高管,创过业,就差没写书了。…

基于 Docker 的深度学习环境:入门篇

这篇文章聊聊如何从零到一安装、配置一个基于 Docker 容器的深度学习环境。 写在前面 这段时间,不论是 NLP 模型,还是 CV 模型,都得到了极大的发展。有不少模型甚至可以愉快的在本地运行,并且有着不错的效果。所以,经…

【数据结构】实现二叉树的基本操作

目录 1. 二叉树的基本操作 2. 具体实现 2.1 创建BinaryTree类以及简单创建一棵树 2.2 前序遍历 2.3 中序遍历 2.4 后序遍历 2.5 层序遍历 2.6 获取树中节点的个数 2.7 获取叶子节点的个数 2.8 获取第K层节点的个数 2.9 获取二叉树的高度 2.10 检测值为val的元素是否…

Fiddler抓取https史上最强教程

有任何疑问建议观看下面视频 2023最新Fiddler抓包工具实战,2小时精通十年技术!!!对于想抓取HTTPS的测试初学者来说,常用的工具就是fiddler。 但是初学时,大家对于fiddler如何抓取HTTPS难免走歪路&#xff…

使用stm32实现电机的PID控制

使用stm32实现电机的PID控制 PID控制应该算是非常古老而且应用非常广泛的控制算法了,小到热水壶温度控制,大到控制无人机的飞行姿态和飞行速度等等。在电机控制中,PID算法用的尤为常见。 文章目录使用stm32实现电机的PID控制一、位置式PID1.计…

史诗级详解面试中JVM的实战

史诗级详解面试中JVM的实战 1.1 什么是内存泄漏?什么是内存溢出?1.2 你们线上环境的JVM都设置多大?1.3 线上Java服务器内存飙升怎么回事?1.4 线上Java项目CPU飙到100%怎么排查?1.5 线上Java项目OOM了,怎么回事?1.1 什么是内存泄漏?什么是内存溢出? 内存溢出:OutOfMe…

JavaScript中的for in和for of的区别(js的for循环)

简述:js中的for循环大家都知道,今天来分享下for in和for of在使用时区别和注意事项,顺便做个笔记; 测试数据 //数组const arr [1, 2, 3, 4, 5]//对象const obj {name: "小李",color: ["plum", "pink&q…

【巨人的肩膀】JAVA面试总结(七)

💪MyBatis 1、谈谈你对MyBatis的理解 Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,加载驱动、创建连接、创建statement等繁杂的过程,开发者开发时只需要关注如何编写SQL语句,可以…

蓝桥杯C/C++VIP试题每日一练之完美的代价

💛作者主页:静Yu 🧡简介:CSDN全栈优质创作者、华为云享专家、阿里云社区博客专家,前端知识交流社区创建者 💛社区地址:前端知识交流社区 🧡博主的个人博客:静Yu的个人博客 🧡博主的个人笔记本:前端面试题 个人笔记本只记录前端领域的面试题目,项目总结,面试技…

Python 十大开源Python库,看看你熟悉几个?

嗨害大家好鸭!我是芝士❤ 对于码农来说, 关注的永远是新近有什么流行的、 既能解决问题又好用的利器。 本文就为你盘点十大开源Python库。 1、Pipenv 第一名非它莫属, 这个工具2017年初才发布, 但它已经能够影响每个Python开发…

菜鸟刷题Day7

⭐作者:别动我的饭 ⭐专栏:菜鸟刷题 ⭐标语:悟已往之不谏,知来者之可追 一.整理字符串:1544. 整理字符串 - 力扣(LeetCode) 描述 给你一个由大小写英文字母组成的字符串 s 。 一个整理好的字…

C语言番外-------《函数栈帧的创建和销毁》知识点+基本练习题+完整的思维导图+深入细节+通俗易懂建议收藏

绪论 书接上回,上回我们已经将C语言的所有知识点进行了总结归纳到同一个思维导图中,而本章是一个番外篇,将具体讲述一些更深入的知识。 话不多说安全带系好,发车啦(建议电脑观看)。 附:红色&…

我用Python django开发了一个商城系统,已开源,求关注!

起始 2022年我用django开发了一个商城的第三方包,起名为:django-happy-shop。当时纯粹是利用业余时间来开发和维护这个包,想法也比较简单,Python语言做web可能用的人比较少,不一定有多少人去关注,就当是一个…

我们在操作自动化测如何实现用例设计实例

在编写用例之间,笔者再次强调几点编写自动化测试用例的原则: 1、一个脚本是一个完整的场景,从用户登陆操作到用户退出系统关闭浏览器。 2、一个脚本脚本只验证一个功能点,不要试图用户登陆系统后把所有的功能都进行验证再退出系统…

【开发】后端框架——Dubbo

前置知识: 微服务 Dubbo是高性能的RPC框架,主要目的是支持远程调用 Dubbo Dubbo是一个 高性能和透明化的RPC框架 ,主要目的是支持远程调用,是阿里巴巴SOA服务化治理方案的核心框架 最大的特点是按照分层的方式来 架构 &#xff0c…

LDNet分割模型搭建

原论文:https://arxiv.org/abs/2110.09103源码:https://github.com/unilight/LDNet 直接步入正题~~~ 一、ESA_blcok模块 1、PPM模块 class PPM(nn.Module):def __init__(self, pooling_sizes(1, 3, 5)):super().__init__()self.layer nn.ModuleList…

蓝桥杯刷题冲刺 | 倒计时13天

作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦🐾 文章目录1.母牛的故事2.魔板1.母牛的故事 题目 链接: [递归]母牛的故事 - C语言网 (dotcpp.c…

基于微信小程序+爬虫制作一个表情包小程序

跟朋友聊天斗图失败气急败坏的我选择直接制作一个爬虫表情包小程序,从源头解决问题,从此再也不用担心在斗图中落入下风 精彩专栏持续更新↓↓↓ 微信小程序实战开发专栏 一、API1.1 项目创建1.2 图片爬虫帮助类1.3 测试窗体1.4 接口封装二、小程序2.1 项…

【iOS】GCD再学

文章目录前言GCD概要什么是GCD多线程编程GCD的APIDispatch Queuedispatch_queue_createMain Dispatch Queue/Global Dispatch Queuedispatch_set_target_queuedispatch_afterDispatch Groupdispatch_barrier_asyncdispatch_syncdispatch_applydispatch_suspend/dispatch_resume…