利用先序序列递归构造根节点,利用中序序列来逻辑上判断是构造左子树还是右子树

 

package com.cn.sotred;

/**
 * 采用先序和中序序列构造二叉树
 * 
 * @author wanjn
 *
 */
public class MyTree {
    private Node root;// 根节点

    public Node getRoot() {
        return root;
    }

    public void setRoot(Node root) {
        this.root = root;
    }

    /**
     * 先序序列和中序序列构造二叉树,递归的根据先序序列和中序序列构造根节点, 然后根据逻辑人为的判断是构造左子数还是右子数
     * 
     * @param pre
     *            先序序列
     * @param i
     *            先序序列起点
     * @param j
     *            先序序列终点
     * @param mid
     *            中序序列
     * @param s
     *            中序序列起点
     * @param t
     *            中序序列终点
     */
    public MyTree(int[] pre, int i, int j, int[] mid, int s, int t) {
        root = createTree(pre, i, j, mid, s, t);
    }

    /**
     * 先根遍历
     */
    public void preOrder() {
        doPreOrder(root);
    }


    /**
     * 中根遍历
     */
    public void midOrder() {
        doMidOrder(root);
    }

    /**
     * 后根遍历
     */
    public void lastOrder() {
        doLastOrder(root);
    }


    /**
     * 得到某个节点的所有子孙节点(注意不是真子孙)
     * 
     * @param i
     *            指定节点的节点值
     */
    public void descents(int i) {
        DoDescents(root, i, 0);
    }

    /**
     * 递归方法最后一层需要退出,既可以是正常执行完毕的退出也可以是return的退出
     * 
     * @param node
     */
    private void doPreOrder(Node node) {
        // 先访问根节点
        System.out.print(node.value + " ");
        // 再访问左子树
        if (node.left != null) {
            doPreOrder(node.left);
        }
        // 再访问右子树
        if (node.right != null) {
            doPreOrder(node.right);
        }

    }
    /**
     * 得到某个节点的所有子孙节点(注意不是真子孙) 逻辑为:从根节点开始找,没找到指定节点前,标志位为0,不输出;
     * 找到指定节点后标示位置为1,之后递归该节点左右子树,因为标志位被传递下去,依然为1.标志位为1均输出节点值;
     * 然后在遍历完左右子树后,手动将标志位置为0,接下去继续遍历,因为标志位0,即使遍历了也不会输出节点值
     * 
     * @param node
     *            根节点
     * @param i
     *            指定的节点
     * @param flag
     *            标志位
     */
    private void DoDescents(Node node, int i, int flag) {

        if (node == null) {
            return;
        }
        // 开始
        if ((Integer) node.value == i) {
            flag = 1;
        }
        if (flag == 1) {
            System.out.print(node.value + "  ");
        }
        DoDescents(node.left, i, flag);
        DoDescents(node.right, i, flag);
        // 结束
        if ((Integer) node.value == i) {
            flag = 0;
        }
    }

    private void doLastOrder(Node node) {
        // 先遍历左子树
        if (node.left != null) {
            doLastOrder(node.left);
        }

        // 再遍历右子树
        if (node.right != null) {
            doLastOrder(node.right);
        }
        // 最后遍历根节点
        System.out.print(node.value + " ");
    }
    private Node createTree(int[] pre, int i, int j, int[] mid, int s, int t) {
        if (i > j) {
            return null;
        }
        // k用来在中序序列(从头开始找)中找根的位置
        int k = s;
        // 创建根节点,即先序序列的第一个元素
        Node node = new Node(pre[i]);
        // 在中序序列中查找该根节点的位置,从而确定,新的先序和中序序列
        while (k <= t && mid[k] != pre[i]) {
            k++;
        }
        // 在中序序列中没有找到根节点,说明序列本身有问题
        if (k > t) {
            throw new RuntimeException("不存在序列组合指定的树!");
        }
        // 创建左子树
        // 其中 k-s 表示在中序序列中左子树中节点的个数假设是q,从而可以知道先序序列从根节点开始后面的q个节点都属于左子树;
        // 依次我们可以得到左先,左中 ; 右先,右中的数组对应下标组合
        node.left = createTree(pre, i + 1, i + k - s, mid, s, k - 1);
        node.right = createTree(pre, i + k - s + 1, j, mid, k + 1, t);

        return node;
    }

    private void doMidOrder(Node node) {
        // 先遍历左子树
        if (node.left != null) {
            doMidOrder(node.left);
        }
        // 再遍历根节点
        System.out.print(node.value + " ");
        // 最后遍历右子树
        if (node.right != null) {
            doMidOrder(node.right);
        }
    }

    private class Node {
        Node left;// 左儿子
        Object value;// 节点值
        Node right;// 右儿子

        private Node(Object value) {
            this.value = value;
        }
    }
}

 

 posted on 2018-02-04 23:13  改变一下  阅读(166)  评论(0编辑  收藏  举报