学过数据结构和算法的人都能很快的写出二叉树的三种遍历次序。
那么如果已经知道了遍历的结果,能不能把一颗二叉树重新构造出来呢?
给定一颗二叉树,假设每个节点都用唯一的字符来表示,具体结构如下:
struct Node
{
struct Node* pLeft;
struct Node* pRight;
char value;
};
假设已经有了前序和中序遍历结果,希望通过一个算法重建这个二叉树。
分析:先回忆一下前序和中序遍历的定义。
前序遍历:先访问当前结点,然后以前序遍历顺序访问左子树和右子树。
中序遍历:以中序遍历顺序访问左子树,接着访问当前节点,然后以中序遍历顺序访问右子树。
根据定义,可以发现如下规律:
前序遍历的每一个节点,都是当前子树的根节点。同时,以对应的结点为边界,就会把中序遍历结果
分为左子树和右子树。
前序:a b d c e f a是根节点
中序:d b a e c f a是根节点,把字符串分成左右两个子树
实现:
/**/
//定义树的长度
#define TREELEN 6
#include<iostream>
using namespace std;
struct Node
{
struct Node* pLeft;
struct Node* pRight;
char value;
};
void Rebuild(char *pPreOrder,//前序遍历结果
char *pInorder,//中序遍历结果
int nTreeLen,//树的长度
Node **pRoot)//根节点
{
//检查边界条件
if(pPreOrder==NULL ||pInorder==NULL)
{
return ;
}
//获得前序遍历的第一个结点
Node *pt=new Node ;
pt->value=*pPreOrder;
pt->pLeft=NULL;
pt->pRight=NULL;
//如果根节点为空,将该节点设置为根节点,首次会调用
if(*pRoot==NULL)
{
*pRoot=pt;
}
//如果深度为1,那么已经是叶节点了
if(nTreeLen==1)
{
return;
}
//在中序遍历中寻找左子树
char *pOrgInOrder=pInorder;
char *pLeftEnd=pInorder;
int ntemp=0;
//找到左子树的结尾
while(*pPreOrder!=*pLeftEnd)
{
if(pPreOrder==NULL||pLeftEnd==NULL)
{
return;
}
ntemp++;
if(ntemp>nTreeLen)
{
return;
}
pLeftEnd++;
}
//确定左子树的长度
int nLeftLen=0;
nLeftLen=(int)(pLeftEnd-pOrgInOrder);
//确定右子树的长度
int nRightLen=0;
nRightLen=nTreeLen-nLeftLen-1;
//重建左子树
if(nLeftLen>0)
{
Rebuild(pPreOrder+1,pInorder,nLeftLen,&((*pRoot)->pLeft));
}
//重建右子树
if(nRightLen>0)
{
Rebuild(pPreOrder+nLeftLen+1,pInorder+nLeftLen+1,nRightLen,&((*pRoot)->pRight));
}
}
int main()
{
char PreOrder[]={'a','b','d','c','e','f'};
char InOrder[]={'d','b','a','e','c','f'};
Node *root=NULL;
Rebuild(PreOrder,InOrder,TREELEN,&root);
}