二叉树的深度优先遍历(先、中、后序方式-递归和非递归)和广度优先遍历

31 篇文章 0 订阅
package cn.alex.demo;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

/**
 * 树的遍历方式 深度优先遍历:递归和非递归两种 广度优先遍历:
 * 
 * @author AlexDiner
 *
 */
public class PrintTree {
    public static void main(String[] args) {

        TreeNode tree = createTree();
        // System.out.println("递归方式先序遍历:");
        // ForeachTree.rePreTree(tree);
        // System.out.println("非递归方式先序遍历:");
        // ForeachTree.nRePreTree(tree);
        // System.out.println("递归方式中序遍历:");
        // ForeachTree.reInTree(tree);
        // System.out.println("非递归方式中序遍历:");
        // ForeachTree.nReInTree(tree);
        // System.out.println("递归方式后序遍历:");
        // ForeachTree.reEndTree(tree);
        // System.out.println("非递归方式后序遍历:");
        // ForeachTree.nReEndTree(tree);
        System.out.println("广度优先遍历:");
        ForeachTree.BFSTree(tree);
    }

    /**
     * 创建一个用作测试的树
     * 
     * @return
     */
    public static TreeNode createTree() {

        /*
         * 示例: 
         *          1 
         *      2       3 
         *    4   5    6  7 
         *  8      9
         */
        TreeNode root = new TreeNode(1);
        TreeNode left1Tree = new TreeNode(2);
        TreeNode left2Tree = new TreeNode(4);
        TreeNode left3Tree = new TreeNode(8);
        TreeNode left4Tree = new TreeNode(6);
        TreeNode right1Tree = new TreeNode(5);
        TreeNode right2Tree = new TreeNode(9);
        TreeNode right3Tree = new TreeNode(3);
        TreeNode right4Tree = new TreeNode(7);
        left2Tree.leftNode = left3Tree;
        right1Tree.rightNode = right2Tree;
        left1Tree.leftNode = left2Tree;
        left1Tree.rightNode = right1Tree;
        right3Tree.leftNode = left4Tree;
        right3Tree.rightNode = right4Tree;
        root.leftNode = left1Tree;
        root.rightNode = right3Tree;
        return root;

    }
}

class ForeachTree {

    /**
     * 先序遍历:根左右的顺序--递归方式
     * 
     * @param tree
     */
    public static void rePreTree(TreeNode tree) {
        if (tree != null) {
            System.out.println(tree.val);
            rePreTree(tree.leftNode);
            rePreTree(tree.rightNode);
        }
    }

    /**
     * 先序遍历:根左右的顺序--非递归方式
     * 思路:
     * 1. 获取当前节点,首先输出当前节点,然后将其两个节点压入栈中,然后利用栈的先进后出的特性,弹出节点并获取其子节点
     * 2. 在此判断条件为当前节点不为空,若为空则直接结束本次循环然后进行下一次循环
     * @param tree
     */
    public static void nRePreTree(TreeNode tree) {
        // 创建栈,由于深度遍历是
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(tree);
        while (stack != null && !stack.isEmpty()) {
            TreeNode te = stack.pop();
            System.out.println(te.val);
            List<TreeNode> trees = te.getChildren();
            if(trees == null) continue;
            for(TreeNode t:trees) {
                if(t!=null) {
                    stack.push(t);
                }
            }
        }

    }

    /**
     * 中序遍历:左根右的顺序--递归方式
     * 
     * @param tree
     */
    public static void reInTree(TreeNode tree) {
        if (tree != null) {
            reInTree(tree.leftNode);
            System.out.println(tree.val);
            reInTree(tree.rightNode);
        }
    }

    /**
     * 中序遍历:左根右的顺序--非递归方式
     * 思路:
     * 1. 由于中序遍历方式为左根右,所以先判断当前节点是否有左子节点,若有的话将当前节点的左子节点置为空(防止下次遍历到重复判
     * 断)再压入栈,然后将当前节点的左子节点压入栈,一次类推
     * 2. 直到当前节点没有左子节点时,输出当前节点的值,然后判断是否有右子节点,若有的话则继续进行压栈操作(在此有一技巧之处在
     * 于若该节点的左右子节点都没有的话,则不需要将当前节点压入栈--在第一次获取当前节点时已经将当前节点弹出了)
     * 3. 注:只有在当前节点有左子节点时需要将当前节点压入栈,因为遍历顺序为左中右,所以在当前节点有左节点时,需要再进行回根节
     * 点查找输出根节点的值,若当前节点没有左节点时,则不需要记录上一节点
     * @param tree
     */
    public static void nReInTree(TreeNode tree) {
        // 创建栈,由于深度遍历是
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(tree);
        while(stack != null && !stack.isEmpty()) {
            TreeNode root = stack.pop();
            if(root.leftNode != null) {
                TreeNode left = root.leftNode;
                root.leftNode = null;
                stack.push(root);
                stack.push(left);
            }else {
                System.out.println(root.val);
                if(root.rightNode != null) {
                    TreeNode right = root.rightNode;
                    stack.push(right);
                }
            }
        }
    }

    /**
     * 后序遍历:左右根的顺序--递归方式
     * 
     * @param tree
     */
    public static void reEndTree(TreeNode tree) {
        if (tree != null) {
            reEndTree(tree.leftNode);
            reEndTree(tree.rightNode);
            System.out.println(tree.val);
        }
    }

    /**
     * 后序遍历:左右根的顺序--非递归方式
     * 
     * @param tree
     */
    public static void nReEndTree(TreeNode tree) {
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(tree);
        while( stack != null && !stack.isEmpty()) {

            TreeNode root = stack.pop();
            if(root.leftNode != null) {
                TreeNode left = root.leftNode;
                root.leftNode = null;
                stack.push(root);
                stack.push(left);
            }else if(root.rightNode != null) {
                TreeNode right = root.rightNode;
                root.rightNode = null;
                stack.push(root);
                stack.push(right);
            }else {
                System.out.println(root.val);
            }
        }
    }

    /**
     * 广度优先遍历
     * 
     * @param tree
     */
    public static void BFSTree(TreeNode tree) {
        Deque<TreeNode> queue = new ArrayDeque<TreeNode>();
        queue.push(tree);
        while (queue != null && !queue.isEmpty()) {
            TreeNode root = queue.pop();
            System.out.println(root.val);
            if (root.leftNode != null) {
                queue.add(root.leftNode);
            }
            if (root.rightNode != null) {
                queue.add(root.rightNode);
            }
        }
    }

}

class TreeNode {

    int val;

    public TreeNode(int val) {
        this.val = val;
    }

    TreeNode leftNode;
    TreeNode rightNode;

    /**
     * 获取该节点的所有左右子节点-先右后左
     * 由于所有遍历方式都是从左向右的顺序,所以压入栈时需要先将右子节点压入,后将左子节点压入,
     * 因此在此获取子节点时先添加右子节点,后添加左子节点
     * @return
     */
    public List<TreeNode> getChildren() {
        List<TreeNode> list = new LinkedList<TreeNode>();
        if (this.rightNode != null)
            list.add(this.rightNode);
        if (this.leftNode != null)
            list.add(this.leftNode);
        return list.size() == 0 ? null : list;
    }

}

以上代码如有疑问,可以私聊笔者或留言给笔者,谢谢

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然,二叉树的遍历有三种主要方式序遍历(根-左-右)、序遍历(左-根-右)和后序遍历(左-右-根)。非递归的层次遍历(也叫广度优先遍历,从上到下、从左到右)通常使用队列来辅助实现。 这里分别给出这些遍历的非递归算法代码: 1. 层序遍历(广度优先遍历): ```c #include <stdio.h> #include <stdlib.h> #include <queue> struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; }; void levelOrder(struct TreeNode* root) { if (root == NULL) return; // 使用队列存储每一层的节点 queue<struct TreeNode*> q; q.push(root); while (!q.empty()) { int size = q.size(); for (int i = 0; i < size; i++) { struct TreeNode* node = q.front(); q.pop(); printf("%d ", node->val); // 打印当前节点值 if (node->left != NULL) q.push(node->left); if (node->right != NULL) q.push(node->right); } printf("\n"); // 换行表示新的一层 } } ``` 2. 序遍历(递归非递归两种方式,这里是非递归版本,使用栈): ```c void preorderNonRecursive(struct TreeNode* root) { if (root == NULL) return; stack<struct TreeNode*> s; s.push(root); while (!s.empty()) { struct TreeNode* node = s.top(); s.pop(); printf("%d ", node->val); // 打印当前节点值 if (node->right != NULL) s.push(node->right); if (node->left != NULL) s.push(node->left); } } ``` 3. 序遍历(非递归,同样使用栈): ```c void inorderNonRecursive(struct TreeNode* root) { if (root == NULL) return; stack<struct TreeNode*> s; struct TreeNode* curr = root; while (curr != NULL || !s.empty()) { while (curr != NULL) { s.push(curr); curr = curr->left; } curr = s.top(); s.pop(); printf("%d ", curr->val); // 打印当前节点值 curr = curr->right; } } ``` 4. 后序遍历非递归,使用两个栈): ```c void postorderNonRecursive(struct TreeNode* root) { if (root == NULL) return; stack<struct TreeNode*> s1, s2; s1.push(root); while (!s1.empty()) { struct TreeNode* node = s1.top(); s1.pop(); s2.push(node); if (node->left != NULL) s1.push(node->left); if (node->right != NULL) s1.push(node->right); } while (!s2.empty()) { struct TreeNode* node = s2.top(); s2.pop(); printf("%d ", node->val); // 打印当前节点值 } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值