二叉树的遍历分为前序遍历、中序遍历、后序遍历。先来看一下三种遍历的不同
1前序遍历
(1)访问根节点
(2)前序遍历左子树
(3)前序遍历右子树
2中序遍历
(1)中序遍历左子树
(2)访问根节点
(3)中序遍历右子树
3后序遍历
(1)后序遍历左子树
(2)后续遍历右子树
(3)访问根节点
前序遍历+中序遍历可以求出二叉树的结构;同理后续遍历+中序遍历也可以求出二叉树的结构。但是前序遍历+后续遍历不能求出二叉树的结构。下面以前序遍历+中序遍历来说明一下:
中序遍历的顺序得知,根结点把左右子树分来了,而通过前序遍历有可以得到根结点,这样就可以找到根结点和左右子树的结点,再递归解决左右子树就可以构建二叉树了。
上图中二叉树先序遍历为:ABCDEF
中序遍历为:CBDAEF
假如我们不知道二叉树的结构,通过第一步,我们可以得到
1根结点为A
2左子树结点,左子树先序遍历为BCD,中序遍历为CBD
3右子树结点,右子树先序遍历为EF,中序遍历为EF
如下图
分为两个子问题
(1)左子树问题:先序遍历为BCD,后续遍历为CBD,求左子树
(2)右子树问题:先序遍历为EF,后续遍历为EF,求右子树
递归解决即可。
那为什么先序遍历+后续遍历不能构建出二叉树呢?
很显然,先序遍历+后续遍历只能找到根节点,并不能把左子树和右子树区分开来,所以无法构建二叉树。
测试代码:
#include<iostream>
using namespace std;
class Node{
public:
Node(char c):data(c),left(NULL),right(NULL){}
char data;
Node *left;
Node *right;
};
//根据前序遍历+中序遍历,,返回根结点
//PreOrder前序遍历结果
//Inorder中序遍历结果
//length树节点个数
Node *MakeBinTree(char *PreOrder, char *InOrder, int length)
{
if(length<=0)
return NULL;
Node *T;//根结点
int t;//根结点在中序遍历中的位置
for(t=0;PreOrder[0]!=InOrder[t];t++);//找到根几点在中序遍历中的位置
T=new Node(PreOrder[0]);
//递归解决左子树
T->left=MakeBinTree(PreOrder+1,InOrder,t);//左子树长度为t,不是t-1,因为下标从0开始
//递归解决右子树
T->right=MakeBinTree(PreOrder+t+1,InOrder+t+1,length-t-1);
return T;
}
//后续遍历输出结点信息
void LastOrder(Node *T)
{
if(T==NULL)
return ;
LastOrder(T->left);
LastOrder(T->right);
cout<<T->data<<",";
}
int main()
{
char *PreOrder="ABCDEF";
char *InOrder="CBDAEF";
//后续遍历一下,构建二叉树是否正确
Node *T=MakeBinTree(PreOrder,InOrder,6);
LastOrder(T);
return 0;
}