题目描述:给定二叉树的前序序列和中序序列--假设没有重复的字符,写一个算法重建这课二叉树。
要求:struct Node{
Node *m_pLeft;
Node *m_pRight;
char m_nValue;
};
举例:
前序:a b d c e f
中序:d b a e c f
重构的二叉树:
分析:
前序遍历:先访问当前节点,然后前序访问左子树,右子树。
中序遍历:先中序遍历左子树,接着访问当前节点,然后以中序遍历右子树。
根据前序遍历和中序遍历的特点,可以发现如下规律:
前序遍历的每一个节点,都是当前子树的根节点。同时,以对应的节点为边界,就会把中序遍历的序列分隔为左子树和右子树。
前序:a b d c e f,a是根节点
中序:d b a e c f,a是根节点,将中序序列分成两个子树
这样,如果能够找到前序遍历中对应的左右子树,就可以把作为当前的根节点,然后依次递归下去,这样就能够依次恢复左右子树。
代码如下:
struct Node
{
char m_nValue;
Node *m_pLeft;
Node *m_pRight;
};
Node *construct(char *startPreOrder,char *endPreOrder,char *startInOrder,char *endInOrder)
{
//首先取得根节点,然后建立根节点
char rootValue=*startPreOrder;
Node *root=new Node;
root->m_nValue=rootValue;
root->m_pLeft=root->m_pRight=NULL;
//退出条件:当子树仅仅有一个节点。要检测输入是否有效
if(startPreOrder==endPreOrder)
{
//感觉statInOrder==endInOrder这个判断条件可以不要
if(*startPreOrder==*startInOrder)
return root;
else
throw exception("Invalid input");
}
//找到根节点之后,需要从中序序列中查找根节点,有可能找不到,计算左子树长度
char *rootInOrder=startInOrder;
while(rootInOrder<endInOrder && *rootInOrder!=rootValue)
++rootInOrder;
if(rootInOrder==endInOrder && *rootInOrder!=rootValue)
throw exception("Invalid input");
int leftLength=rootInOrder-startInOrder;
char *leftPreOrderEnd=startPreOrder+leftLength;
//构建左子树和右子树
if(leftLength>0)
root->m_pLeft=construct(startPreOrder+1,leftPreOrderEnd,startInOrder,rootInOrder-1);
if(leftLength<endPreOrder-startPreOrder)
root->m_pRight=construct(leftPreOrderEnd+1,endPreOrder,rootInOrder+1,endInOrder);
return root;
}
Node *construct(char *preOrder,char *inOrder,int length)
{
if(preOrder==NULL || inOrder==NULL || length<0)
return NULL;
return construct(preOrder,preOrder+length-1,inOrder,inOrder+length-1);
}
调用代码:
int main()
{
char pre[]="abc";
char in[]="cba";
Node *root=NULL;
try{
root=construct(pre,in,sizeof(pre));
}catch(exception e){
cout<<e.what()<<endl;
}
return 0;
}