问题描述
听课到树的遍历,当其与二叉树的遍历联系起来时,一个问题困惑着我:为什么树的后根遍历对应的是二叉树的中序遍历?我的思考如下:
树与二叉树
定义不多讲,这里再介绍以下普通树与二叉树之间的转换(其实就是孩子兄弟表示法),注意理解转换时的特性:
转换成二叉树:
- 左子树是孩子
- 右子树是兄弟
- 左边到右边的过程即是树->二叉树的转化
- 右边到左边的过程即是二叉树->树的转化
- 注意观察到几个特性:
- 指定结点若有孩子,对应的在二叉树中也一定有孩子,且一定在该结点左子树的右臂上,且其左子树的根结点一定为指定结点最左边的孩子。(臂:如图中的结点B、C、D组成的整体,这里我把它称为右臂)
- 指定结点若有兄弟结点,对应的在二叉树中一定是在该结点所在的右臂上
- 树(子树)的左臂对应的在二叉树上左臂不动
//树的存储孩子 兄弟表示法
typedef struct CSNode{
ElemType data; //数据域
struct CSNode *firstchild, *nextsibling; //第一个孩子和右兄弟指针
}CSNode, *CSTree;
树的遍历
先根遍历:若树非空,先访问根结点,再依次(从左至右)对每棵子树进行先根遍历。
后根遍历:若树非空,先依次(从左至右)对每棵子树进行后根遍历,最后再访问根结点。
思考:树的遍历与二叉树遍历之间的联系
看以下例子即可发现树的遍历和二叉树遍历的联系和区别:
前者为普通树:
- 先根遍历为:DHIJ
- 不可能有中序。(和二叉树只有两个子树不同,普通的树可能有三甚至更多个子树,何谈中序之说)
- 后根遍历:HIJD
后者为二叉树:
- 先序遍历为:DHIJ(对应先根遍历)
- 中序遍历为:HIJD(对应后根遍历)
- 后序遍历为:JIHD
深入理解,有两个问题:
1、为什么二叉树后序遍历没有对应树的某种遍历方式呢?
因为二叉树的先序遍历和中序遍历都有一个很重要的先后顺序,是后序遍历没有的:访问根结点一定在访问右子树之前!也就是说,对于一个右臂来说,它上面结点被访问的顺序一定是由浅入深的(例:H I J)!对应的在普通树中,就是一定是从左至右的访问每个子树,这至关重要,因为这是先根、后根遍历所规定的。但后序遍历这个顺序是反着的,也就是对应到普通树中,是从右至左的访问每个子树,显然不符合要求。
2、接上问思考,访问根结点、左子树的顺序有要求吗(这也是区分先序和中序遍历的关键)?
答案是没有。这个顺序可以理解成到底是让左子树的头头(左孩子,右臂最上面的结点)看根结点的屁股,还是让根结点看左子树尾巴(右臂最下面的结点)的屁股。因为先序遍历,根结点的后继一定是它的左孩子(右臂最上面的结点);中序遍历,根结点的前驱一定是左子树右臂最下面的那个结点。那么对应到树的遍历,先根、后根的问题不就是让根结点跟在它的孩子们前面还是后面的问题嘛。而我们所谓的右臂,正是根结点的孩子们啊。树的遍历与二叉树遍历对应的关系也就知道了。
3、其他
由此,还有一个可能很重要的发现:先、中、后序遍历中,我们规定,一定是先访问左子树再访问右子树,那么也就是说对于同一个根结点的两棵树,左子树上结点的前驱一定不会在右子树上,右子树上结点的后继一定不会在左子树上。
如有错误欢迎评论区指正。