Java 二叉树的遍历方式(前序、中序、后序的递归与非递归,广度遍历)

示例树(下面的所有代码都基于此树型结构)
这里写图片描述

二叉树节点

/**
 * 二叉树节点
 * @author hong
 *
 */
public class BinaryTree {

    public BinaryTree lChild;
    public BinaryTree rChild;
    public String data;

    public BinaryTree(BinaryTree lChild, BinaryTree rChild, String data) {
        this.lChild = lChild;
        this.rChild = rChild;
        this.data = data;
    }

    /**
     * 访问方法
     */
    public void visit() {
        System.out.println(this.toString());
    }

    @Override
    public String toString() {
        return "【"+this.data+"】  ";
    }
}

示例树工厂(得到一棵示例树)

/**
 * 示例树工厂
 * @author hong
 *
 */
public class BinaryTreeFactory {

    /**
     * 构造示例树
     * @return 根节点A
     */
    public static BinaryTree createTree() {
        BinaryTree E = new BinaryTree(null, null, "E");
        BinaryTree C = new BinaryTree(E, null, "C");

        BinaryTree D = new BinaryTree(null, null, "D");
        BinaryTree B = new BinaryTree(null, D, "B");

        BinaryTree A = new BinaryTree(B, C, "A");

        return A;
    }

}

1 先序遍历

所谓的先序遍历指的就是先遍历根节点再遍历左节点最后遍历右节点。
用先序遍历遍历示例树过程:

1.ABC
2.ABDC
3.ABDCE

先序遍历递归算法

    /**
     * 先序遍历的递归算法
     * @param root
     */
    public static void preRecursion(BinaryTree root) {
        if(root == null) {
            return;
        }
        root.visit();
        preRecursion(root.lChild);
        preRecursion(root.rChild);
    }

先序遍历非递归算法

    /**
     * 先序遍历的非递归算法
     * 利用栈
     * @param root
     */
    public static void preNonRecursion(BinaryTree root) {
        Stack<BinaryTree> stack = new Stack<>();
        stack.push(root);

        while(!stack.isEmpty()) {
            root = stack.pop();
            root.visit();
            if(root.rChild != null) { // 由于是先需要遍历左节点,按照出栈的顺序则左节点后入栈
                stack.push(root.rChild);
            }
            if(root.lChild != null) {
                stack.push(root.lChild);
            }
        }
    }

2 中序遍历

中序遍历指的就是先遍历左节点再遍历根节点最后遍历右节点。
使用中序遍历遍历示例树过程:

1.BAC
2.BDAC
3.BDAEC

中序遍历递归算法

    /**
     * 中序遍历递归算法
     * @param root
     */
    public static void midRecursion(BinaryTree root) {
        if(root == null) {
            return;
        }
        if(root.lChild != null) {
            midRecursion(root.lChild);
        }
        root.visit();
        if(root.rChild != null) {
            midRecursion(root.rChild);
        }
    }

中序遍历非递归算法

    /**
     * 中序遍历非递归算法
     * @param root
     */
    public static void midNonRecursion(BinaryTree root) {
        Stack s = new Stack();
        BinaryTree temp = root;
        while(temp != null || !s.isEmpty()) {
            if(temp != null) {
                s.push(temp);
                temp = temp.lChild;
            } else {
                temp = (BinaryTree) s.pop();
                temp.visit();
                temp = temp.rChild;
            }
        }
    }

3 后序遍历

后序遍历指的就是先遍历左节点再遍历右节点最后遍历根节点。
使用后序遍历遍历示例树过程:

1.BCA
2.DBCA
3.DBECA

后序遍历递归算法

    /**
     * 后序递归算法
     * @param root
     */
    public static void backRecursion(BinaryTree root) {
        if(root == null) {
            return;
        }
        if(root.lChild != null) {
            backRecursion(root.lChild);
        }
        if(root.rChild != null) {
            backRecursion(root.rChild);
        }
        root.visit();
    }

后序遍历非递归算法

    /**
     * 后序遍历非递归算法
     * 后序遍历非递归由于是先遍历左子节点再遍历右子节点最后再遍历当前节点,在进行出栈时不知道
     * 是当前的左节点或者右节点,所以需要一个另外的栈来存储信息,以进行判断。
     * @param root
     */
    public static void backNonRecursion(BinaryTree root) {
        Stack<BinaryTree> leftStack = new Stack<>();
        Stack<BinaryTree> rightStack = new Stack<>();

        leftStack.push(root);

        // 当两个栈的其中一个有数据就继续遍历
        while(!leftStack.empty() || !rightStack.empty()) {

            // 如果leftStackPeekNode中最上面的节点为叶子节点则直接打印
            if(leftStack.peek().lChild == null && leftStack.peek().rChild == null) {
                BinaryTree popNode = leftStack.pop(); // 出队该节点
                popNode.visit();

                // 如果出队的是右侧队列的左节点或者右侧队列的第一个节点只有一个节点则把右侧节点也出队
                if(popNode == rightStack.peek().lChild || (rightStack.peek().lChild == null && rightStack.peek().rChild == popNode)) {
                    rightStack.pop().visit();
                }
            } else { // 最上面的节点不为叶子节点则把该节点的子节点放入该队列并把这个节点放到右侧的栈中
                // 左侧队列不为空
                if(!leftStack.empty()) {
                    if(leftStack.peek().rChild != null) {
                        leftStack.push(leftStack.peek().rChild);
                    }
                    if(leftStack.peek().lChild != null) {
                        leftStack.push(leftStack.peek().lChild);
                    }
                    rightStack.push(leftStack.pop());
                } else { // 左侧队列为空则对右侧队列进行出队
                    rightStack.pop().visit();
                }
            }
        }
    }

层次遍历

    /**
     * 对二叉树进行层次遍历
     * 首先利用一个队列的数据结构进行对二叉树层次遍历的实现
     * @param root
     */
    public static void levelTraversal(BinaryTree root) {
        Queue<BinaryTree> queue = new LinkedList<>();
        queue.add(root);
        while(queue.size() > 0) {
            BinaryTree node = queue.poll();
            node.visit();

            if(node.lChild != null) {
                queue.add(node.lChild);
            }

            if(node.rChild != null) {
                queue.add(node.rChild);
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/ZHLittleRed/article/details/80109766