面试题6:重建二叉树

来源:互联网 发布:mac怎么卸载java 编辑:程序博客网 时间:2024/05/16 08:16
题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并输出它的后序遍历序列。

struct BinaryTreeNode{    int             m_nValue;    BinaryTreeNode * m_pLeft;    BinaryTreeNode * m_pRight;}; 

思路:根据前序遍历和中序遍历的规律,前序遍历中第一个元素是根节点,在中序遍历中找到这个元素,在这个元素之前的数字就是这个元素的左结点,后面的是它的右结点。

之后再利用递归,对左结点和右结点分别做同样的操作。


前序遍历:1,2,4,7,3,5,6,8

中序遍历:4,7,2,1,5,3,8,6

(1)根节点是1,在中序遍历中找到1,1之前的4 7 2都是1的左结点,5 3 8 6都是1的右结点,所以1有3个左结点,4个右结点,在前序遍历中1之后的3个数使它左结点,最后4个数是它右结点,所以可以划分为

左结点的前序遍历2 4 7

左结点的中序遍历4 7 2

右结点的前序遍历3 5 6 8

右结点的中序遍历5 3 8 6

(2)对划分之后的序列做同样的步骤,先找出根节点,即前序遍历中的第一个元素2,2就是当前的根节点,中序遍历中2在最后一个位置,所以它没有右结点,右结点数为0不构建右子树,左结点有2个,构建左子树

再划分为 4 7(前序)和4 7(中序)

(3)再划分,4是根节点,中序遍历7在4之后,所以是它右结点,左结点数为0,不构建它的左子树,构建右子树

(4)创建结点,并设置value为7,前序遍历和中序遍历都只剩一个7,所以将当前结点返回,4的右结点7已构建好向上返回,即2的左子树已构建完毕,因为2的右子树为0,所以继续向上返回,即根节点的左子树已构建完毕,之后在对根节点的右子树做同样的步骤即可。


struct BinaryTreeNode{    int             m_nValue;    BinaryTreeNode * m_pLeft;    BinaryTreeNode * m_pRight;}; //(前序遍历起始位置,前序遍历结束位置,中序遍历起始位置,中序遍历结束位置)BinaryTreeNode* ConstructCore(int * startPreorder,int * endPreorder,int * startInorder,int * endInorder){//前序遍历的第一个元素是根节点的值int rootValue=startPreorder[0];BinaryTreeNode * root=new BinaryTreeNode();root->m_nValue=rootValue;root->m_pLeft=root->m_pRight=NULL;//如果前序遍历起始位置等于结束位置,即只要一个元素if(startPreorder==endPreorder){///如果前序遍历中只剩一个元素,那么中序遍历中也只有一个元素,并且它们元素值是相等的if(startInorder==endInorder&&*startInorder==*startPreorder)return root;else//不相等抛出异常throw exception("invalid input");}int * rootInorder=startInorder;//在中序遍历中找到根节点的值while(rootInorder<=endInorder&&*rootInorder!=rootValue)rootInorder++;//如果遍历完毕但没有找到根节点的值,抛出异常if(rootInorder==endInorder && *rootInorder!=rootValue)throw exception("invalid input");int leftLength=rootInorder-startInorder;//根据中序遍历计算当前结点左子树的结点数int * leftPreorderEnd=startPreorder+leftLength;//左子树的结点在前序遍历中的结束位置 //递归构建左右子树if(leftLength>0){//构建左子树root->m_pLeft=ConstructCore(startPreorder+1,leftPreorderEnd,startInorder,rootInorder);}if(leftLength<endPreorder-startPreorder){//构建右子树root->m_pRight=ConstructCore(leftPreorderEnd+1,endPreorder,rootInorder+1,endInorder);}}BinaryTreeNode * Construct(int * preorder,int * inorder,int length){if(preorder==NULL||inorder==NULL||length<=0){return NULL;}return ConstructCore(preorder,preorder+length-1,inorder,inorder+length-1);}


代码步骤:

(1)保存前序遍历中第一个元素的值value

(2)创建节点,并将value赋值给节点,左右子树设为null

(3)判断前序遍历中是否只剩一个元素,如果是再判断和当前中序遍历序列中的第一个元素是否相等,不相等抛出异常,相等返回之前创建的结点,如果不止一个元素继续执行下一步

(4)根据value找出根节点在中序遍历中的位置rootInOrder

(5)判断是否找到,没有找到抛出异常,找到继续下一步

(6)根据根节点在中序遍历的位置,计算出左结点的个数和右结点的个数

(7)根据左右结点的个数计算出要划分的位置

(8)递归构建左右子树


0 0
原创粉丝点击