根據前序遍歷和中序遍歷,後序遍歷和中序遍歷重構二叉樹
重構二叉樹目前主要是採取遞迴的方式
只能通過前序,中序 或者 後續,中序進行重構
前序和後序是不能夠重構的,因為在得知根節點後只有中序遍歷才能確定左子樹和右子樹的數目
二叉樹的幾種遍歷
前序遍歷:根結點 —> 左子樹 —> 右子樹
中序遍歷:左子樹—> 根結點 —> 右子樹
後序遍歷:左子樹 —> 右子樹 —> 根結點
層次遍歷:只需按層次遍歷即可
根據前序遍歷和中序遍歷重構二叉樹:
輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。
前序遍歷第一位是根節點;
中序遍歷中,根節點左邊的是根節點的左子樹,右邊是根節點的右子樹。
所以,根節點 是{ 1 };
左子樹是:前序{ 2,4,7 } ,中序{ 4,7,2 };
右子樹是:前序{ 3,5,6,8 } ,中序{ 5,3,8,6 };
根據這個我們可以得出二叉樹的形狀
這時,如果我們把左子樹和右子樹分別作為新的二叉樹,則可以求出其根節點,左子樹和右子樹。
這樣,一直用這個方式,就可以實現重建二叉樹。
解題步驟
1、前序遍歷的第一個節點即為根節點
2、根據根節點,在中序遍歷中找出左子樹和右子樹,並統計左子樹和右子樹的個數
3、遞迴構建左子樹和右子樹
根據前序遍歷得出根節點,根據中序遍歷確定左子樹和右子樹的個數
public class RebuildBinaryTree {
//假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字
/*
前序遍歷第一位是根節點;
中序遍歷中,根節點左邊的是根節點的左子樹,右邊是根節點的右子樹。
例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6}。
首先,根節點 是{ 1 };
左子樹是:前序{ 2,4,7 } ,中序{ 4,7,2 };
右子樹是:前序{ 3,5,6,8 } ,中序{ 5,3,8,6 };
這時,如果我們把左子樹和右子樹分別作為新的二叉樹,則可以求出其根節點,左子樹和右子樹。
*/
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if(pre==null||in==null){
return null;
}
TreeNode treeNode=reConstructBinaryTree(pre, in,0,pre.length-1,0,in.length-1);
return treeNode;
}
public TreeNode reConstructBinaryTree(int [] pre,int [] in,int preStart,int preEnd,int inStart,int inEnd) {
TreeNode tree=new TreeNode(pre[preStart]); //前序遍歷的第一個是根節點,遞迴時把左子樹和右子樹分別作為新的二叉樹
tree.left=null;
tree.right=null;
if(preStart==preEnd&&inStart==inEnd){ //說明已經是樹葉節點
return tree;
}
int root;
for(root=inStart;root<inEnd;root++){ //尋找根節點在中序遍歷中的下標
if(pre[preStart]==in[root]){
break;
}
}
int leftLength=root-inStart; //左子樹的長度
int rightLength=inEnd-root; //右子樹的長度
//把左子樹和右子樹分別作為新的二叉樹,則可以求出其根節點,左子樹和右子樹。
if(leftLength>0){
tree.left=reConstructBinaryTree(pre,in,preStart+1,preStart+leftLength,inStart,root-1);
}
if(rightLength>0){
tree.right=reConstructBinaryTree(pre,in,preStart+1+leftLength,preEnd,root+1,inEnd);
}
return tree;
}
}
根據後序遍歷和中序遍歷重構二叉樹:
輸入某二叉樹的後序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的後序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入後序遍歷序列{7,4,2,5,8,3,6,1}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。
思路是一樣的:
解題步驟
1、後序遍歷的最後一個節點即為根節點
2、根據根節點,在中序遍歷中找出左子樹和右子樹,並統計左子樹和右子樹的個數
3、遞迴構建左子樹和右子樹
public class RebuildBinaryTree {
//假設輸入的後序遍歷和中序遍歷的結果中都不含重複的數字
/*
後序遍歷最一位是根節點;
中序遍歷中,根節點左邊的是根節點的左子樹,右邊是根節點的右子樹。
例如輸入後序遍歷序列{7,4,2,5,8,6,3,1}和中序遍歷序列{4,7,2,1,5,3,8,6}。
首先,根節點 是{ 1 };
左子樹是:後序{ 7,4,2} ,中序{ 4,7,2 };
右子樹是:後序{ 5,8,6,3} ,中序{ 5,3,8,6 };
這時,如果我們把左子樹和右子樹分別作為新的二叉樹,則可以求出其根節點,左子樹和右子樹。
*/
public TreeNode reConstructBinaryTree(int [] end,int [] in) {
if(end==null||in==null){
return null;
}
TreeNode treeNode=reConstructBinaryTree(end, in,0,end.length-1,0,in.length-1);
return treeNode;
}
public TreeNode reConstructBinaryTree(int [] end,int [] in,int endStart,int endEnd,int inStart,int inEnd) {
TreeNode tree=new TreeNode(end[endEnd]); //後序遍歷的最後一個是根節點,遞迴時把左子樹和右子樹分別作為新的二叉樹
tree.left=null;
tree.right=null;
if(endStart==endEnd&&inStart==inEnd){ //說明已經是樹葉節點
return tree;
}
int root;
for(root=inStart;root<inEnd;root++){ //尋找根節點在中序遍歷中的下標
if(end[endStart]==in[root]){
break;
}
}
int leftLength=root-inStart; //左子樹的長度
int rightLength=inEnd-root; //右子樹的長度
//把左子樹和右子樹分別作為新的二叉樹,則可以求出其根節點,左子樹和右子樹。
if(leftLength>0){
tree.left=reConstructBinaryTree(end,in,endStart,endStart+leftLength-1,inStart,root-1);
}
if(rightLength>0){
tree.right=reConstructBinaryTree(end,in,root,endEnd-1,root+1,inEnd);
}
return tree;
}
}