您的位置:首页 > Web前端

【剑指offer】重建二叉树&&二叉树的递归与非递归遍历

2017-03-05 22:55 746 查看
前序遍历:先根节点,左子结点,右子节点。

中序遍历:先左子节点,根节点,右子节点。

后序遍历:先左子结点,右子节点,根节点。

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

import java.util.Stack;

class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
return reConTree(pre,0,pre.length-1,in,0,in.length-1);
}
public TreeNode reConTree(int[] pre,int preleft, int preright,int[] in,int inleft,int inright){
if(preleft>preright||inleft>inright){
return null;
}
TreeNode root = new TreeNode(pre[preleft]);
for(int i=inleft;i<=inright;i++){
if(pre[preleft]==in[i]){
//构建左子树,区间长度为(i-inleft),先序区间为[preleft+1,preleft+(i-inleft)],中序区间为[inleft,i-1]
root.left=reConTree(pre,preleft+1,preleft+(i-inleft),in,inleft,i-1);
//构建右子树,区间长度为(inright-i),先序区间为[左子树右区间+1,先序右区间末],中序区间为[i+1,inright];
root.right=reConTree(pre,preleft+(i-inleft)+1,preright,in,i+1,inright);
}
}
return root;
}

/**
* 递归遍历二叉树
* @param node
*/

public static void traverseBinTree(TreeNode node){
if (node==null){
return;
}
//System.out.println(node.val);          //前序遍历
if(node.left!=null){
traverseBinTree(node.left);
}
//System.out.println(node.val);          //中序遍历
if(node.right!=null){
traverseBinTree(node.right);
}
System.out.println(node.val);         //后序遍历
}
/**
* 非递归版先序遍历
*
* 即对于任一结点,其可看做是根结点,因此可以直接访问。
* 访问完之后,若其左孩子不为空,按相同规则访问它的左子树
* 当访问其左子树时,再访问它的右子树。
*
* @param node
*/
public static void preOrder(TreeNode node){
Stack<TreeNode> tree = new Stack<TreeNode>();
while(node!=null || !tree.empty()){
while(node!=null){
System.out.println(node.val);
tree.push(node);
node = node.left;
}
if(!tree.empty()){
node = tree.pop();
node = node.right;
}
}
}
/**
* 非递归版中序遍历
*
* 对于任一结点,优先访问其左孩子,而左孩子结点又可以看做一根结点。
* 然后继续访问其左孩子结点,直到遇到左孩子结点为空的结点才进行访问。
* 按相同的规则访问其右子树。
*
* @param node
*/
public static void inOrder(TreeNode node){
Stack<TreeNode> tree = new Stack<TreeNode>();
while(node!=null || !tree.empty()){
while(node!=null){
tree.push(node);
node = node.left;
}
if(!tree.empty()){
node = tree.pop();
System.out.println(node.val);
node = node.right;
}
}
}
/**
* 非递归版后序遍历1
*
* 要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。
* 如果P不存在左孩子和右孩子,则可以直接访问它;
* 或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。
* 若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候。
* 左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
*
* @param node
*/
public static void postOrder(TreeNode node){
Stack<TreeNode> tree = new Stack<TreeNode>();
TreeNode pre = null;  //前一个访问的节点
TreeNode cur ;   //当前节点
tree.push(node);
while(!tree.empty()){
cur = tree.peek();  //访问栈顶元素
//如果当前结点没有孩子结点(情况一)或者孩子节点都已被访问过 (情况二)[pre!=null]
if((cur.left==null&&cur.right==null)||(pre!=null&&(pre==cur.left||pre==cur.right))){
System.out.println(cur.val);
tree.pop();
pre = cur;
}else{
//注意入栈先后顺序,右子节点点先入栈
if(cur.right!=null){
tree.push(cur.right);
}
if(cur.left!=null){
tree.push(cur.left);
}
}
}
}
/**
* 非递归版后序遍历2
*
* 对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点。
* 此时该结点出现在栈顶,但是此时不能将其出栈并访问,因此其右孩子还为被访问。
* 所以接下来按照相同的规则对其右子树进行相同的处理。
* 当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。
*
* @param node
*/
public static void postOrder2(TreeNode node){
Stack<TreeNode> tree = new Stack<TreeNode>();
Stack<Integer> counts = new Stack<Integer>();
Integer i = new Integer(1);
while(node != null || !tree.empty()){
while(node!=null){
tree.push(node);
counts.push(new Integer(0));
node = node.left;
}
while(!tree.empty()&&counts.peek().equals(i)){
counts.pop();
System.out.println(tree.pop().val);
}
if(!tree.empty()){
counts.pop();
counts.push(new Integer(1));  //标记有访问右孩子
node = tree.peek();
node = node.right;
}
}

}
public static void main(String[] args) {
int[] pre = new int[]{1,2,4,7,3,5,6,8};
int[] in = new int[]{4,7,2,1,5,3,8,6};
TreeNode tree = new Solution().reConstructBinaryTree(pre, in);
postOrder(tree);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 二叉树 遍历