树的遍历非递归实现

java 树的遍历非递归实现

public class TreeToSequence {

    public int[][] convert(Node root) {
        //特殊输入
        if (root == null) {
            return null;
        }

        //由于树的结点数目不知道,因此遍历过的结点只能存放在集合list中,之后再转存到数组中
        List<Node> preOrderList = new ArrayList<Node>();
        List<Node> inOrderList = new ArrayList<Node>();
        List<Node> afterOrderList = new ArrayList<Node>();

        //对以root为根结点的二叉树进行遍历,将遍历过的结点依次放入到preOrderList中
        this.preOrder(root, preOrderList);
        this.inOrder(root, inOrderList);
        this.afterOrder(root, afterOrderList);

        //创建一个二维数组用于返回结果
        int[][] results = new int[3][preOrderList.size()];

        //集合list不能直接转化为int[]数组,因此要遍历集合取出元素放入到数组中
        //注意细节:get(i)得到的是结点对象,而返回的是节点的值
        for (int i = 0; i < preOrderList.size(); i++) {
            results[0][i] = preOrderList.get(i).getDate();
            results[1][i] = inOrderList.get(i).getDate();
            results[2][i] = afterOrderList.get(i).getDate();
        }

        //不要忘记返回结果
        return results;
    }

    /**
     * 对以root为根结点的二叉树进行先序遍历,将遍历过的结点依次放入到preOrderList中
     */
    private void preOrder(Node root, List<Node> preOrderList) {
        //①创建一个栈,菱形符
        Stack<Node> stack = new Stack<>();
        //②创建指针cur表示当前正在访问的结点,初始值为root
        Node cur = root;
        //③将根结点放入栈中
        stack.push(cur);
        //④循环,弹栈--右左结点入栈--弹栈……
        while (!stack.isEmpty()) {
            //从栈顶弹出一个结点node
            cur = stack.pop();
            //弹出的元素就是当前遍历的元素,将其放入到集合中
            preOrderList.add(cur);
            //如果弹出元素node有右元素,则入栈
            if (cur.getRightChild() != null) {
                stack.push(cur.getRightChild());
            }
            //如果弹出元素node有左元素,则入栈
            if (cur.getLeftChild() != null) {
                stack.push(cur.getLeftChild());
            }
        }
    }

    /**
     * 对以root为根结点的二叉树进行中序遍历,将遍历过的结点依次放入到inOrderList中
     */
    private void inOrder(Node root, List<Node> inOrderList) {
        //①创建一个栈用来存放结点
        Stack<Node> stack = new Stack<>();
        //②创建变量指针cur表示当前正在访问的结点,cur初始值为root
        Node cur = root;
        //③将根结点放入栈中
        stack.push(cur);
        //④循环:当stack不为空就继续循环
        while (!stack.isEmpty()) {
            //⑤循环,如果左结点不为null就将结点放入栈中
            while (cur != null) {
                //先取左结点再放入栈中
                cur = cur.getLeftChild();
                //注意这里cur!=null并不表示cur.left!=null,因此要重新判断,只有left不为null才放入栈中,否则结束循环
                if (cur != null) {
                    stack.push(cur);
                }
            }
            //当左结点为null,即左结点遍历完成后
            //从栈中弹出结点,这就是当前遍历的结点,放入集合
            cur = stack.pop();
            inOrderList.add(cur);

            //取弹出结点的右结点,判断是否为null,如果不为null则同root一样放入stack中
            cur = cur.getRightChild();
            if (cur != null) {
                stack.push(cur);
            }
            //如果有结点为null,则通过循环继续弹出结点再取有右结点即可,直到stack为空
        }
    }

    /**
     * 对以root为根结点的二叉树进行后序遍历,将遍历过的结点依次放入到afterOrderList中
     */
    private void afterOrder(Node root, List<Node> afterOrderList) {
        //①创建2个栈用于存放结点
        Stack<Node> stack1 = new Stack<>();
        Stack<Node> stack2 = new Stack<>();
        //②创建临时变量cur表示当前正在变量的结点,初始值为root
        Node cur = root;
        //③将根结点先放入栈中
        stack1.push(cur);
        //④循环--逻辑类似先序遍历
        while (!stack1.isEmpty()) {
            //先弹出栈顶元素,放入stack2
            cur = stack1.pop();
            stack2.push(cur);

            //再将其左、右结点放入栈中
            if (cur.getLeftChild() != null) {
                stack1.push(cur.getLeftChild());
            }
            if (cur.getRightChild() != null) {
                stack1.push(cur.getRightChild());
            }
        }

        //此时树的结点都在stack2中,将其放入到集合中
        while (!stack2.isEmpty()) {
            afterOrderList.add(stack2.pop());
        }
    }
}

点赞