作者:小树苗渴望变成参天大树
作者宣言:认真写好每一篇博客
作者gitee:gitee
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!
前言
今天我们来讲一讲非线性的一种数据结构,大家肯定对这种结构充满好奇和不解,今天我就带大家来解决这个问题,我所将的是树以及二叉树这种结构,本篇着重讲解关于树的相关概念,带小白先入个门,我们开始进入正文。
一、树概念及结构
1.1树的概念
树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
有一个特殊的结点,称为根结点,根节点没有前驱结点
除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1<= i <= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继
我们来看看树的图:
这是现实中的树
数据结构中的图:
我们来看看那些不是树:
注意:树形结构中,子树之间不能有交集,否则就不是树形结构
1.2 树的相关概念
1.节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6
2.叶节点或终端节点:度为0的节点称为叶节点; 如上图: B、 C、H、I…等节点为叶节点
3.非终端节点或分支节点:度不为0的节点; 如上图:D、E、F、G…等节点为分支节点
4.双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点
5.孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点
6.兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点
7.树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6
8.节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
9.树的高度或深度:树中节点的最大层次; 如上图:树的高度为4
10.堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:H、I互为兄弟节点
11.节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先
12.子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙
13.森林:由m(m>0)棵互不相交的树的集合称为森林;
相信看到这里大家对树有了一定的认识。
1.3 树的表示
我们上面知道了树是什么,那我们怎么表示他呢??今天我就使用图的形式来给大家展示。
我们之前学过单链表,把定义单链表的结构想象成树,第一个节点就是根节点,其余每个节点只有一个孩子的树,然后再来想一下树的定义结构。多了几个指针来存储他的孩子节点而已。
我们看到上面树的结构是非常复杂的,有的人就想定义一个结构体,定义指针来存储此节点的孩子节点,但是我们不知道这个节点有多少个孩子,你定义的这个结构体可能只适用于一个节点,其余节点就不满足
有点牛人就想出来一个厉害的方法,不管你有几个孩子节点我都可以给你表示出来。左孩子右兄弟
我们来看看他的具体逻辑图,方便理解:
具体看定义实现:
typedef int DataType;
struct Node
{
struct Node* _firstChild1; // 第一个孩子结点
struct Node* _pNextBrother; // 指向其下一个兄弟结点
DataType _data; // 结点中的数据域
};
今天我们就将树的定义,关于树的操作我不做重点介绍,因为树的操作不是重点,我们重点操作的是二叉树,接下来会介绍。
1.4树在实际中的运用(表示文件系统的目录树结构)
再我们文件系统里面用的最多
二、二叉树概念及结构
2.1概念
一棵二叉树是结点的一个有限集合,该集合:
- 或者为空
- 由一个根节点加上两棵别称为左子树和右子树的二叉树组成
具体一点就是一个树的节点最多只有两个孩子,或者是一个空树。
- 二叉树不存在度大于2的结点
- 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树
我们来看看哪些是二叉树:
我们再来看看现实中的二叉树:
我们再来看看两种特殊的二叉树:
- 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是 ,则它就是满二叉树。
- 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。
2.2 二叉树的性质
1.若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1)个结点.
- 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^h-1
我们使用错位相减法来解决这个证明,后面有好多证明都需要使用错位相减法,不会的赶紧熟悉一下
3.对任何一棵二叉树, 如果度为0其叶结点个数为 , 度为2的分支结点个数为 ,则有n0 =n2 +1;
- 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h= . (ps: 是log以2为底,n+1为对数)
因为是满二叉树,总结点的是2^h-1,再计算的时候可以不带1,所以直接取对数得深度
- 对于具有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否则无右孩子
2.3 二叉树的存储结构
2.3.1链式存储
我们上面讲到树的存储结构,左孩子右兄弟法,那我们二叉树只有两个孩子,我们可以采取定义左右孩子的指针,来保存两个孩子结点,这就是二叉树的链式存储:
二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址(也成二叉链式)
typedef int BTDataType;
// 二叉链
struct BinaryTreeNode
{
struct BinTreeNode* _pLeft; // 指向当前节点左孩子
struct BinTreeNode* _pRight; // 指向当前节点右孩子
BTDataType _data; // 当前节点值域
}
我们的链式存储还有一个存储方式是三叉链式,多了一个指针域指向其父亲:
struct BinaryTreeNode
{
struct BinTreeNode* _pParent; // 指向当前节点的双亲
struct BinTreeNode* _pLeft; // 指向当前节点左孩子
struct BinTreeNode* _pRight; // 指向当前节点右孩子
BTDataType _data; // 当前节点值域
};
今天我们依旧不讲他的操作,我们只讲他的存储,操作再之后的博客会讲到
2.3.2顺序存储
普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。
我们刚才讲到的性质5就派上用场了,我们来看图
我们看到顺序存储只适用满二叉树,这样不会造成空间浪费,但是大部分时候我们看到的都是非满二叉树,那么顺序存储就没有意义了吗??当然不是,再我接下来讲的堆的时候就会排上用场了
三、总结
今天关于树的概念以及存储方式,还有二叉树的概念,性质,存储方式,我也给大家解释清楚了,希望不懂的读者可以仔细的去学学,接下来一篇我讲重点介绍堆,希望大家可以来支持博主。文章来源:https://www.toymoban.com/news/detail-785164.html
文章来源地址https://www.toymoban.com/news/detail-785164.html
到了这里,关于【数据结构】-关于树的概念和性质你了解多少??的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!