一、树结构的定义与对比
树结构是一种一对多的非线性结构,它是由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 指针域来解决。
文收录于数据结构理解与实现
下期带来二叉树的理解与实现。如果文章对你有帮助记得点赞收藏关注