题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
java参考代码如下:
public static TreeNode construct(int[] preorder,int[] inorder){
if(preorder==null || inorder==null || preorder.length==0 || preorder.length!=inorder.length)
return null;
return constructCore(preorder,0,preorder.length-1,inorder,0,inorder.length-1);//第一次的根,左右都是两端
}
public static TreeNode constructCore(int[] preorder,int pLeft,int pRight,int[] inorder,int iLeft,int iRight){//注意左右的区间
if(pLeft>pRight||iLeft>iRight)
return null;
int i=0;
for(i=iLeft;i<=iRight;i++){//考虑到每次迭代,起点和终点不同,用变量来区别
if(inorder[i]==preorder[pLeft]){//找到根节点,退出
break;
}
}
TreeNode node = new TreeNode(preorder[pLeft]);
node.left = constructCore(preorder,pLeft+1,pLeft+i-iLeft,inorder,iLeft,i-1);
node.right = constructCore(preorder,pLeft+i-iLeft+1,pRight,inorder,i+1,iRight);
return node;
}
仍然参考以上链接,补充一道由中序遍历和后续遍历,重建二叉树的解答:
public static TreeNode construct(int[] postorder,int[] inorder){
if(postorder==null || inorder==null || postorder.length==0 || postorder.length!=inorder.length)
return null;
return constructCore(postorder,0,postorder.length-1,inorder,0,inorder.length-1);
}
public static TreeNode constructCore(int[] postorder,int pLeft,int pRight,int[] inorder,int iLeft,int iRight){
if(pRight<pLeft||iRight<iLeft)
return null;
int i=0;
for(i=iLeft;i<=iRight;i++){
if(postorder[pRight]==inorder[i])
break;
}
TreeNode node=new TreeNode(postorder[pRight]);
node.left=constructCore(postorder,pLeft,pLeft+i-iLeft-1,inorder,iLeft,i-1);
node.right=constructCore(postorder,pLeft+i-iLeft,pRight-1,inorder,i+1,iRight);
return node;
}
完整代测试版本如下:
package chapter2;
import java.util.List;
/**
* Created by ryder on 2017/6/20.
* 重新编辑时间 2019/03/28
* 重建二叉树:
* 可以完成重建,而前序+后序无法完成
*/
public class P62_ConstructBinaryTree {
//前序+中序
public static TreeNode construct(int[] preorder,int[] inorder){
if(preorder==null || inorder==null || preorder.length==0 || preorder.length!=inorder.length)
return null;
return constructCore(preorder,0,preorder.length-1,inorder,0,inorder.length-1);
}
public static TreeNode constructCore(int[] preorder,int pLeft,int pRight,int[] inorder,int iLeft,int iRight){
if(pLeft>pRight||iLeft>iRight)
return null;
int i=0;
for(i=iLeft;i<=iRight;i++){
if(preorder[pLeft]==inorder[i])
break;
}
TreeNode node=new TreeNode(preorder[pLeft]);
node.left=constructCore(preorder,pLeft+1,pLeft+i-iLeft,inorder,iLeft,i-1);
node.right=constructCore(preorder,pLeft+i-iLeft+1,pRight,inorder,i+1,iRight);
return node;
}
//后续+中序
public static TreeNode construct2(int[] postorder,int[] inorder){
if(postorder==null || inorder==null || postorder.length==0 || postorder.length!=inorder.length)
return null;
return constructCore2(postorder,0,postorder.length-1,inorder,0,inorder.length-1);
}
public static TreeNode constructCore2(int[] postorder,int pLeft,int pRight,int[] inorder,int iLeft,int iRight){
if(pRight<pLeft||iRight<iLeft)
return null;
int i=0;
for(i=iLeft;i<=iRight;i++){
if(postorder[pRight]==inorder[i])
break;
}
TreeNode node=new TreeNode(postorder[pRight]);
node.left=constructCore(postorder,pLeft,pLeft+i-iLeft-1,inorder,iLeft,i-1);
node.right=constructCore(postorder,pLeft+i-iLeft,pRight-1,inorder,i+1,iRight);
return node;
}
public static void preprinttree(TreeNode root){
if(root==null) return;
System.out.print(" "+root.val);
if(root.left!=null)
preprinttree(root.left);
if(root.right!=null)
preprinttree(root.right);
}
public static void main(String[] args){
int[] pre={1,2,4,7,3,5,6,8};
int[] in={4,7,2,1,5,3,8,6};
TreeNode root = construct(pre,in);
preprinttree(root);//先序遍历验证
}
}
二叉树节点的定义如下:
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
}
在想清楚如何在前序遍历和中序遍历序列中确定左、右子树的子序列之后,可以写出如下的递归代码:
BinaryTreeNode* Construct(int* preorder,int* inorder,int length)
{
if(preorder==nullptr || inorder==nullptr || length<=0) return nullptr;
return ConstructCore(preorder,preorder+length-1,inorder,inorder+length-1);
}
BinaryTreeNode* ConstructCore(itn* startPreorder,int* endPreoder,int* startInorder,int* endInorder)
{
//前序遍历序列的第一数字是根节点的值
int rootValue=startPreorder[0];
BinaryTreeNode* root=new BinaryTreeNode();
root->m_nValue=rootValue;
root->m_pLeft=root->m_pRight=nullptr;
//前序遍历序列只有根节点一个数值
if(startPreorder==endPreoder)
{
if(startInorder==endInorder && *startPreorder==*startInorder)
return root;
else
throw std::exception("Invalid input.");
}
//在中序遍历序列中找到根节点的值
int* rootInorder=startInorder;
while(rootInorder<=endInorder && *rootInorder!=rootValue)
++rootInorder;
if(rootInorder==endInorder && *rootInorder!=rootValue)
throw std::exception("Invalid input.");
int leftLength=rootInorder-startInorder;
int* leftPreorderEnd=startInorder+leftLength;
if(leftLength>0)
{
//构建左子树
root->m_pLeft= ConstructCore(startPreorder+1,leftPreorderEnd,startInorder,rootInorder-1);
}
if(leftLength<endPreoder-startPreorder)
{
//构建右子树
root->m_pRight= ConstructCore(leftPreorderEnd+1,endPreoder,rootInorder+1,endInorder);
}
return root;
}
测试用例:
a.普通二叉树(完全二叉树;不完全二叉树)。
b.特殊二叉树(所有节点都没有有子节点的二叉树;所有节点都没有左子节点的二叉树;只有一个节点的二叉树)。
c.特殊输入测试(二叉树的根节点指针为nullptr ;输入的前序遍历序列和中序遍历序列不匹配)。