树
结点的度:一个结点含有的子树的个数称为该结点的度;
树的度:一棵树中,最大的结点的度称为树的度;
叶结点或终端结点:度为0的结点称为叶结点;
无序树:树中任意节点的子结点之间没有顺序关系,这种树称为无序树,也称为自由树;
有序树:树中任意节点的子结点之间有顺序关系,这种树称为有序树;
二叉树
每个结点的度不超过2的有序树
满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树。高度为k,并且有(2^k)-1个结点。
完全二叉树:若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
二叉树存储结构
顺序存储结构
这种存储方式对于满二叉树和完全二叉树是非常合适也是高效方便的。
但是对于一般的二叉树而言,必须用“虚结点”将一棵二叉树补成一棵完全二叉树来存储。否则无法确定结点之间的前驱后续关系,这样一来就会造成空间的浪费。所以常用 链表 来表示二叉树。
链式存储结构
二叉链表
通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址。
三叉链表
为了方便访问某结点的双亲,还可以给链表结点增加一个双亲字段parent,用来指向其双亲结点。
这种存储结构既便于查找孩子结点,又便于查找双亲结点;
但是,相对于二叉链表存储结构而言,它增加了空间开销。
二叉树的遍历
有先序、中序、后序遍历,左右结点的顺序总是先左后右,先序、中序、后序中的先、中、后可以理解为根节点的位置,来方便记忆遍历顺序,
先序遍历:
⑴ 访问根结点;
⑵ 遍历左子树;
⑶ 遍历右子树。
中序遍历:
⑴遍历左子树;
⑵访问根结点;
⑶遍历右子树。
后序遍历:
⑴遍历左子树;
⑵遍历右子树;
⑶访问根结点。
由遍历结果恢复二叉树
1)确定根节点位置
2)除去根节点位置,把其他部分分为左右两子树部分(只给出前后序时,除去根节点后左右子树部分连在一起,这个较难处理,作为笔试题人工分辨时比较方便,通过编程实现的话,个人思路是,将各个结点代表的符号数值化,将前序除去结点后剩余部分和后序除去结点后剩余部分各自逐个相加,数值相同时,便是左右子树的分界处)
3)将左右子树分别重复上述操作
举例:
前序:abcdefgh
后序:cefdbhga
通过前后遍历易知根结点为a;
除去根结点后:
前序:(a) bcdefgh
后序:cefdbhg (a)
将字母数值化,比如强转为int;这里为了计算方便按照字母对应位置赋值(a-1,b-2,c-3…)
b | c | d | e | f | g | h |
---|---|---|---|---|---|---|
2 | 2+3=5 | 5+4=9 | 9+5=14 | 14+6=20 | 7 | 7+8=15 |
c | e | f | d | b | h | g |
---|---|---|---|---|---|---|
3 | 3+5=8 | 8+6=14 | 14+4=18 | 18+2=20 | 8 | 8+7=15 |
可以看出bcdef与cdfdb分别为根结点的左子树部分的先序遍历和后序遍历,gh和hg属于根结点的右子树部分的先序遍历和后序遍历,按照这个方法继续分析,即可还原二叉树。
参考
https://www.cnblogs.com/yw-ah/p/5872516.html
https://baike.baidu.com/item/树/2699484?fr=aladdin