• 题目描述:

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{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就是根结点的值,根据中序遍历,找到根结点的值的位置。根据中序遍历的特点,在根结点值1前边的3个数字都是左子树结点的值,位于1后边的数字都是右子树结点的值。那么,在前序遍历中,根结点1后边的3个数字就是左子树结点的值,再后边的所有数字都是右子树结点的值。这样,我们就在前序遍历和中序遍历两个序列中,分别找到了左子树、右子树对应的前序遍历的子序列和中序遍历的子序列。接下来,就可以用递归的方法来分别构建左子树和右子树了,过程如下图。

     

    enter description here

     

     

     

    enter description here

     

     

    简单总结:从前序中确定根节点,然后在中序中找到根,从而将中序序列分为左右子树的中序遍历序列;再根据左右子树节点的个数,在前序遍历中将前序序列分为左右子树的前序遍历序列,接下来就是递归过程。
    接下来还有一点要考虑的就是鲁棒性了,通过列举各种可能的测试用例来考虑。比如几种特殊的情况是否会导致程序崩溃?1、输入序列的指针为空或长度length为0;2、输入的序列不匹配;3、以及用各种不同形状的二叉树检验程序正确性(完全二叉树、普通二叉树、所有结点只有左(右)孩子的树)
    代码如下:

    BinaryTreeNode* ConstructBinaryTree(int* preorder, int* inorder, int length)
      {
      	// 输入空指针或长度小于等于0时返回NULL
      	if (preorder == NULL || inorder == NULL || length <= 0)
      		return NULL;
      
      	// 创建根结点,前序序列中的第一个值为根结点的值
      	BinaryTreeNode* root = new BinaryTreeNode();
      	root->m_nValue = preorder[0];
      	root->m_pLeft = NULL;
      	root->m_pRight = NULL;
      
      	// 只有一个结点的情况
      	if (length == 1 && *preorder == *inorder)
      		return root;
      	else if (length == 1 && *preorder != *inorder)
      		throw exception("Invalid input");
      
      	// 在中序序列中找到根结点的位置
      	int* rootinorder = inorder;
      	int inorderlength = 0;
      	while (*rootinorder != root->m_nValue && inorderlength < length)
      	{
      		++rootinorder;
      		++inorderlength;
      	}
      	if (inorderlength == length && *rootinorder != root->m_nValue)
      		throw exception("Invalid input");
      
      	int leftlength = rootinorder - inorder;
      	int rightlength = length - leftlength - 1;
      	if (leftlength > 0)
      	{ //构建左子树
      		root->m_pLeft = ConstructBinaryTree(preorder+1,inorder,leftlength);
      	}
      	if (rightlength > 0)
      	{ //构建右子树
      		root->m_pRight = ConstructBinaryTree(preorder+leftlength+1,rootinorder+1,rightlength);
      	}
      	return root;
      }
    
 posted on 2017-04-26 16:44  Bill_LHR  阅读(267)  评论(0编辑  收藏  举报