数据结构中“树”的全面讲解


一、树结构的定义与对比

​ 树结构是一种一对多的非线性结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

  • 不要与现实中的树混在一起,当n>0时,树有且只有一个根结点。
  • 除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1<= i <= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继

树结构图

在这里插入图片描述

树结构的相关概念:

节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6
叶节点或终端节点:度为0的节点称为叶节点; 如上图:B、C、H、I…等节点为叶节点
非终端节点或分支节点:度不为0的节点; 如上图:D、E、F、G…等节点为分支节点
双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点
孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点
兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点
树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
树的高度或深度:树中节点的最大层次; 如上图:树的高度为4
堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:H、I互为兄弟节点
节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先
子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙
森林:由m(m>0)棵互不相交的树的集合称为森林;

对比线性表与树结构,他们有很大的区别。

线性结构 树结构
第一个元素/根结点 前无结点 无双亲,根节点唯一
最后一个元素/叶结点 后无结点 无孩子,可以有多个叶结点
中间元素/中间结点 前一个结点,后一个结点 一个双亲多个孩子

此外树的操作与线性结构也有很大不同,例如求树的深度,树的双亲,树兄弟,叶结点个数等。

树结构在实际中的应用(表示文件目录):

在这里插入图片描述

二、树的存储结构是什么,都有哪些存储结构?

​ 存储结构有两种,一种是采用顺序存储(顺序表),一种是链式存储(链表),对于线性表来说,只需要一对一进行链接遍历即可,树结构与之不同的,树结构的存储位置无法直接反映逻辑关系,挨在一块的有可能是双亲,也有可能是孩子,简单的顺序存储不能满足树的实现要求。

​ 不过要是充分的利用顺序存储和链式存储的特点,还是可以实现树的存储,介绍三种表示法:双亲表示法,孩子表示法,孩子兄弟表示法。

双亲表示法:

​ 每个人都可能有一个或多个孩子,但每个人只有一个双亲,双亲表示法采用顺序表存储树,,同时在每个结点中,附设一个指示器指示其双亲结点到链表中的位置。也就是说,每个结点除了知道自己是谁外,还要知道自己的双亲在哪里。

在这里插入图片描述

//树的双亲表示法结点结构定义
#define MAX_TREE_SIZE 100
typedef int TElemType;   	//树结点的数据类型,目前暂定整形
typedef struct PTNode{
    
        	//结点结构
TElemType   data;  			//数据
	int parent;             //双亲位置
}PTNode;
typedef struct{
    
                  //树结构
	PTNode nodes[MAX_TREE_SIZE];  //结点数组
	int  r,n;                     //根节点的位置和结点数
}

有了这样的结构定义,我们就可以实现双亲定义法了。由于跟结点没有双亲,所以我们约定根结点的位置域设置为-1,这就意味着,我们所有结点都直到他双亲的位置。如图的树结构和双亲表示法的图表。

在这里插入图片描述

孩子表示法:

孩子表示法存储普通树采用的是 “顺序表+链表” 的组合结构,其存储过程是:从树的根节点开始,使用顺序表依次存储树中各个节点,与双亲表示法不同,孩子表示法会给各个节点配备一个链表,用于存储各节点的孩子节点位于顺序表中的位置。 如果节点没有孩子节点(叶子节点),则该节点的链表为空链表。

例图:

在这里插入图片描述

代码实现

#define TElemType char
typedef struct CTNode{
    
    
    //链表中每个结点存储的不是数据本身,而是数据在数组中存储的位置下标。
    int child;
    struct CTNode * next;
}ChildPtr;
typedef struct {
    
    			//结点的数据类型
    TElemType data;			//孩子链表的头指针
    ChildPtr* firstchild;
}CTBox;
typedef struct{
    
    				//存储结点的数组
    CTBox nodes[MAX_SIZE];	//结点数量和树根的位置
    int n,r;
}CTree;

孩子兄弟表示法:

树结构中,位于同一层的节点之间互为兄弟节点。 孩子兄弟表示法,采用的是链式存储结构,其存储树的实现思想是:从树的根节点开始,依次用链表存储各个节点的孩子节点和兄弟节点。 因此,该链表中的节点应包含以下 3 部分内容: 节点的值; 指向孩子节点的指针; 指向兄弟节点的指针;

代码实现:

#define ElemType char
typedef struct CSNode{
    
    
    ElemType data;
    struct CSNode * firstchild,*nextsibling;
}CSNode,*CSTree;

图例:

在这里插入图片描述

这种方法给查找某结点的某个孩子带来了方便,只需要通过firstchild 找到此结点的左儿子,然后再通过左儿子找到二弟,一直下去,知道找到具体的孩子。当然,如果想要找到双亲,完全可以增加一个parent 指针域来解决。

img

文收录于数据结构理解与实现

下期带来二叉树的理解与实现。如果文章对你有帮助记得点赞收藏关注

猜你喜欢

转载自blog.csdn.net/qq_65596720/article/details/130894314