二叉树的前序遍历、中序遍历、后序遍历(递归与非递归java写法)、层次遍历(BFS、DFS写法)

节点类:

@AllArgsConstructor
    public class TreeNode {
    
    
        Object val;
        TreeNode left;
        TreeNode right;
    }

测试类树结构
在这里插入图片描述

测试代码:

@Test
    public void testTree(){
    
    
        TreeNode root = new TreeNode("A", new TreeNode("B", new TreeNode("D", null, null), new TreeNode("E", null, null))
                , new TreeNode("C", new TreeNode("F", null, null), null));
    }

二叉树的前序遍历:

打印节点顺序:根节点→左子树→右子树
访问顺序图:A→B→D→E→C→F
在这里插入图片描述

递归代码:

 	/**
     * 先序遍历(递归)
     * @param root 当前树节点
     */
         public void preOrderRecursive(TreeNode root) {
    
    
        if (root == null) {
    
    
            return;
        }
        // 输出当前节点
        System.out.print("->" + root.val);
        preOrderRecursive(root.left);
        preOrderRecursive(root.right);
    }

非递归:将每个当前的右节点与左节点分别入栈(注意要右节点先,因为栈是先进后出,我这里只用双端队列当作栈。)

非递归代码:

/**
     * 先序遍历(非递归)
     * @param root 当前树节点
     */
    public void preOrderNonRecursive(TreeNode root){
    
    
        Deque<TreeNode> deque = new LinkedList<>();
        if(root != null){
    
    
            deque.addFirst(root);
        }
        while (!deque.isEmpty()){
    
    
            // 出栈并且保存节点
            TreeNode cur = deque.pollFirst();
            System.out.print("->"+cur.val);
            if(cur.right != null){
    
    
                deque.addFirst(cur.right);
            }
            if(cur.left != null){
    
    
                deque.addFirst(cur.left);
            }
        }
        }

输出结果:

在这里插入图片描述

中序遍历:

打印节点顺序:左子树→根节点→右子树
访问顺序图:D→B→E→A→F→C
(其特点:打印顺序为每个节点垂直到同一条水平线上,即为打印顺序)
在这里插入图片描述

递归代码:

	/**
     * 中序遍历(递归)
     *
     * @param root 当前根节点
     */
    public void mediumOrderRecursion(TreeNode root) {
    
    
        if (root == null) {
    
    
            return;
        }
        mediumOrderRecursion(root.left);
        System.out.print("->" + root.val);
        mediumOrderRecursion(root.right);
    }

非递归写法:先通过栈存进每个节点的左子树。然后在从栈中取出(此时栈取得节点应为底层的因为栈是后进先出)。然后对每个取出的节点取其的右节点。如果存在则将其打印,这样直到栈为空,则为所要输出结果。

非递归代码:

	/**
     * 中序遍历(非递归)
     * @param root 当前节点
     */
    public void mediumOrderNonRecursion(TreeNode root){
    
    
        Deque<TreeNode> deque = new LinkedList<>();
        while(root != null || !deque.isEmpty()){
    
    
            while (root != null){
    
    
                deque.addFirst(root);
                root = root.left;
            }
            if(!deque.isEmpty()){
    
    
                TreeNode cur = deque.pollFirst();
                System.out.print("->"+cur.val);
                root = cur.right;
            }
        }
    }

输出结果:

在这里插入图片描述

后序遍历:

访问节点顺序:左子树→右子树→根节点
访问顺序图:D→E→B→F→C→A
在这里插入图片描述

递归代码:

/**
     * 后序遍历(递归)
     * @param root 当前节点
     */
    public void postorderRecursive(TreeNode root) {
    
    
        if (root == null) {
    
    
            return;
        }
        postorderRecursive(root.left);
        postorderRecursive(root.right);
        System.out.print("->" + root.val);
    }

非递归:需要两个栈,一个栈调整节点顺序,一个栈储存最后的结果。构建思路推荐从最简单的两层的满二叉树考虑。

非递归代码:

	/**
     * 后序遍历(非递归)
     * @param root 当前节点
     */
    public  void postorderNonRecursive(TreeNode root){
    
    
        Deque<TreeNode> tempDeque = new LinkedList<>();
        Deque<TreeNode> resDeque = new LinkedList<>();
        if(root != null){
    
    
            tempDeque.addFirst(root);
        }
        while(!tempDeque.isEmpty()){
    
    
            root = tempDeque.pollFirst();
            resDeque.addFirst(root);
            if(root.left != null){
    
    
                tempDeque.addFirst(root.left);
            }
            if(root.right != null){
    
    
                tempDeque.addFirst(root.right);
            }
        }
        while(!resDeque.isEmpty()){
    
    
            System.out.print("->"+(resDeque.pollFirst().val));
        }

    }

输出结果:

在这里插入图片描述

层次遍历

打印节点顺序:A > B > C > D > E > F
BFS写法:用一个队列对每一层的节点进行存储

BFS代码:

	/**
     * BFS层次遍历
     */
    public List<List<Object>> levelTraversal(TreeNode root){
    
    
        // 用来遍历节点的队列
        Deque<TreeNode> deque = new LinkedList<>();
        if(root == null){
    
    
            return new ArrayList<>();
        }
        deque.addFirst(root);
        int count = deque.size();
        List<List<Object>> res = new ArrayList<>();
        while(!deque.isEmpty() ) {
    
    
            ArrayList<Object> temp = new ArrayList<>();
            while(count > 0){
    
    
                TreeNode cur = deque.pollLast();
                temp.add(cur.val);
                count--;
                if(cur.left != null){
    
    
                    deque.addFirst(cur.left);
                }
                if(cur.right != null){
    
    
                    deque.addFirst(cur.right);
                }
            }
            count = deque.size();
            res.add(temp);

        }
        return res;
    }

DFS写法:将储存结果的列表当作引用传进去,并记下此时的节点的层数,也当作引用传进去。这样每次递归根据层数赋值就可得到结果。

DFS代码:

  public List<List<Object>> levelTraversalDFS(TreeNode root) {
    
    

        List<List<Object>> res = new ArrayList<>();
        helpLevel(0, root, res);
        return res;

    }

    public void helpLevel(int level, TreeNode root, List<List<Object>> res) {
    
    
        if (root == null) {
    
    
            return;
        }
        // 如果层数大于等于列表说明已经过了当前层数
        if (level >= res.size()) {
    
    
            res.add(new ArrayList<Object>());
        }
        res.get(level).add(root.val);
        helpLevel(level + 1, root.left, res);
        helpLevel(level + 1, root.right, res);

    }

输出结果:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45938441/article/details/120062863