一:树
1.定义
树是n个节点的有限集,n=0称为空树,非空树满足这样两个条件:
1.只有一个根节点
2.其余节点可以分为有限个互不相交的有限集,每个集合也都是数.
子树
2.节点
-
定义:树的节点包括数据元素以及子树分支,节点拥有的子树个数叫做节点的度,度=0的节点叫做叶节点(终端节点),度不等于0的节点叫做分支节点(非终端节点),除根节点之外还可以叫做内部节点,树的度是节点中度的最大值,上图节点的度最大值是3,因此树的度是3.
-
关系:节点的子树的根节点,叫做子节点(child),反过来叫做父节点(parent),同一个父节点(双亲节点)的叫做兄弟节点(sibling)
3.其他概念
- 深度:从根节点向子节点,叫做数的层次(level),根节点是第一层,或者说深度是1.
- 有序:如果节点的子树从左到右是固定不能变动的,那么该树成为有序树,否则是无序树.
- 森林:Forest是互不相交的树的有限集,因此一个树的两个子树,也可以看做森林.
二:树的存储
1.双亲表示法
在一段连续的内存空间存储树的节点,每个节点存储数据(data),并且存储父节点的下标(parent),根节点的parent为-1.
这种结构查找父节点很直接,复杂度是O(1),但是如果要找子节点,就得遍历.
如果把子节点的下标也存储呢.把最左边的子节点叫做长子,把它的下标也记录在节点内:
image.png
这样,节点可以找到长子节点,对于度在3以内的树来说,就可以满足了.
但是如果是一个非常关注兄弟之间关系的结构,就不行了,这时候可以再增加一个右兄弟域,来存储右边兄弟节点的下标.
2.孩子表示法
用多重链表来存储树:链表的节点含有一个指针域或两个指针域,指向相邻的节点.现在给节点增加更多的指针域,指向子节点.
第一种方法,可以把树的度作为指针域的个数,但是对于节点的度区别很大的树,这会造成空间上的浪费,但是省去了灵活配置需要的运算,算是用空间换时间.
data是数据,后面全都是子节点的指针域
显然会有很多空间浪费
第二种方法,灵活配置每个节点的指针域个数,使其等于节点的度,这个时候度作为关键信息需要被存在节点内,增加了一个degree,度域.这种方法维护节点变得更加复杂,用时间换空间.
data是数据,degree是度域,后面全都是子节点的指针域
空间利用合理
如何同时解决上面两个问题,现在引出孩子表示法:
首先把每个节点的子节点组织成一个链表,叫做孩子链表,有n个节点,就有n个孩子链表,叶节点的孩子链表是空链表;
然后再讲这些链表的头指针顺序存储,存储单元分为数据域和指针域,指针域存的就是孩子链表的头指针.
孩子表示法
其中:孩子链表的元素分为节点域和next指针,节点是指数据在数组中的下标,next执行兄弟节点的元素;
孩子链表的元素结构
节点表的元素结构
这种结构下,想查找子节点,遍历孩子链表就行了,如果想遍历数,直接遍历节点表就行了,但是这也有问题,那就是查找父节点很麻烦.
3.孩子兄弟表示法
前面从父节点和子节点的角度分析,现在从兄弟节点的角度进行分析.
构建一个节点,分为数据域和两个指针域,一个指向第一个子节点,另一个指向自己的兄弟节点.
用这个结构描述所有的节点,根节点兄弟指针域是空的,叶节点的子节点指针域是空的.如果需要查找父节点,那就再增加一个父节点指针域.
孩子兄弟表示法
可以看到它又构成了一个树形结构,而且这个数的度一定是2,这种方法的优势就是把复杂的树改造成了二叉树,便于利用二叉树的性质.
变成了二叉树
网友评论