根据前序遍历和中序遍历重建二叉树

戏子无情 提交于 2020-02-25 08:00:55

package com.study;

/*
 * 根据二叉树的前序遍历和中序遍历结果重建二叉树
 * 并输出其头节点。假设前序遍历和中序遍历结果中没有重复数字
 * 前序遍历序列:{1,2,4,7,3,5,6,8}
 * 中序遍历序列:{4,7,2,1,5,3,8,6}
 * **/
class TreeNode {
    public int data;
    public TreeNode left;
    public TreeNode right;
    
    public TreeNode() {
        
    }
}


public class suanfa4 {
    
    private static int[] arr1 = {1,2,4,7,3,5,6,8};
    private static int[] arr2 = {4,7,2,1,5,3,8,6};
    public static TreeNode RebuildBinaryTree() {
        TreeNode head = null;
        head = ConstructBTree( head ,arr1, 0, 7, arr2, 0, 7);
        return head;
    }
    
    public static TreeNode ConstructBTree(TreeNode node, int[] pre, int pre_start, int pre_end,
            int[] inorder, int inorder_start, int inorder_end) {
        //System.out.println("pre_start:" + pre_start);
        //System.out.println("pre_end: "+ pre_end);
        /*if(pre_start > pre_end || pre_end > pre.length) 
            return null;*/ 
        /*刚开始想着这里应该增加这样一个递归结束条件,但是在调试的过程中发现,如果增加了的话,则不能将最后
            的叶子节点加到二叉树中,而且后面的判断左子树长度和右子树长度会自然结束递归*/
        TreeNode root = new TreeNode();
        root.data = pre[pre_start]; //找到根节点
        root.left = root.right = null;

        //System.out.println("root :"+ root.data);
        int pos = FindPos(root.data, inorder); //在中序遍历的数组中找到根节点的位置
        int Left_Length = pos - inorder_start;
        int Right_Length = inorder_end - pos;
        //System.out.println("左子树长度" + Left_Length);
        //System.out.println("右子树长度" + Right_Length);
        
        if( Left_Length > 0) {   //存在左子树
            TreeNode LeftRoot = new TreeNode();
            LeftRoot.data = pre[pre_start + 1]; //左根节点
            root.left = ConstructBTree(LeftRoot, pre , pre_start + 1, pre_start + Left_Length, inorder,
                    inorder_start , pos - 1);           
        }
        
        if( Right_Length > 0) { //存在右子树
            TreeNode RightRoot = new TreeNode();
            RightRoot.data = pre[pre_start + Left_Length + 1]; //右根节点
            root.right = ConstructBTree(RightRoot, pre , pre_start + Left_Length + 1 , pre_start + Left_Length
                    + Right_Length - 1, inorder, pos + 1 , inorder_end);
        }
        
        return root;        
    }
    
    public static int FindPos(int num, int arr[]) {
        int i = 0;
        if(arr != null) {
            while(arr[i] != num)
                i++;
            if(arr[i] == num)
                return i;
        }
        
        return -1;      
    }
    
    /*后序遍历*/
    public static void LastOrder(TreeNode head) {
        if( head != null) {
            LastOrder(head.left);
            LastOrder(head.right);
            System.out.println(head.data);
        }
    }
    
    
    public static void main(String[] args) {
        TreeNode tnode = RebuildBinaryTree();
        LastOrder(tnode);
    }
}

费了好半天劲才弄出来,有两点感想:

1.如上图代码中被注释掉的打印语句一样,有时调试程序中的逻辑错误,尤其是令人头大的递归,添加打印语句比单步调试更为简单直白,不然,单步跟踪,调着调着就被绕进去了(智商不高,见谅!)

2.虽然这次是参考着剑指offer上的答案弄出来的,但是还是颇有感触。一定要敢想,坚信一个道理:一切反动派都是纸老虎。尤其是递归,要注意函数的参数。有时候最简单的思路,往往容易被忽视。继续努力!


今天晚上,在牛客网上做剑指offer的题的时候,发现其实自己之前写的代码还可以继续精简一点,看着思路更清晰。

    package com.study;
    
    /*
     * 根据二叉树的前序遍历和中序遍历结果重建二叉树
     * 并输出其头节点。假设前序遍历和中序遍历结果中没有重复数字
     * 前序遍历序列:{1,2,4,7,3,5,6,8}
     * 中序遍历序列:{4,7,2,1,5,3,8,6}
     * **/
    class TreeNode {
        public int data;
        public TreeNode left;
        public TreeNode right;
        
        public TreeNode() {
            
        }
    }


    public class suanfa4 {
        
        private static int[] arr1 = {1,2,4,7,3,5,6,8};
        private static int[] arr2 = {4,7,2,1,5,3,8,6};
        public static TreeNode RebuildBinaryTree() {
            TreeNode head = null;
            //head = ConstructBTree( head ,arr1, 0, 7, arr2, 0, 7);
            head = ConstructBTree(arr1, 0, 7, arr2, 0, 7);
            return head;
        }
        
        public static TreeNode ConstructBTree(int[] pre, int pre_start, int pre_end,
                int[] inorder, int inorder_start, int inorder_end) {
            if(pre_start > pre_end || pre_end > pre.length) 
                return null; 
            TreeNode root = new TreeNode();
            root.data = pre[pre_start]; //找到根节点
            root.left = root.right = null;
    
            int pos = FindPos(root.data, inorder); //在中序遍历的数组中找到根节点的位置
            int Left_Length = pos - inorder_start;
            int Right_Length = inorder_end - pos;
            
            if( Left_Length > 0) {   //存在左子树
                root.left = ConstructBTree (pre , pre_start + 1, pre_start + Left_Length, inorder,
                        inorder_start , pos - 1);           
            }
            
            if( Right_Length > 0) { //存在右子树
                root.right = ConstructBTree(pre , pre_start + Left_Length + 1 , pre_start + Left_Length
                        + Right_Length, inorder, pos + 1 , inorder_end);
            }
            
            return root;        
        }
        
        
        
        
        public static int FindPos(int num, int arr[]) {
            int i = 0;
            if(arr != null) {
                while(arr[i] != num)
                    i++;
                if(arr[i] == num)
                    return i;
            }
            
            return -1;      
        }
        
        /*后序遍历*/
        public static void LastOrder(TreeNode head) {
            if( head != null) {
                LastOrder(head.left);
                LastOrder(head.right);
                System.out.println(head.data);
            }
        }
        
        
        public static void main(String[] args) {
            TreeNode tnode = RebuildBinaryTree();
            LastOrder(tnode);
        }
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!