二叉树的BFS和DFS(递归、非递归)

752 阅读1分钟

二叉树的BFS和DFS

BFS(广度优先搜索)

树的BFS遍历是按层来搜索的

public static void BFS(TreeNode root){
        if(root==null){
            return;
        }
        //使用一个队列来保存每层的数据
        Queue<TreeNode> queue = new LinkedList<>();
        //添加第一层的数据
        queue.offer(root);
        while (!queue.isEmpty()){
            //先拿到一层的节点数量
            int len = queue.size();
            //遍历一层的节点,并把节点的子节点加入到队列
            //因为这个for循环只取出当前层的节点
            //所以for循环结束的时候,queue的头节点就是下一层的节点了
            for (int i = 0; i < len; i++) {
                TreeNode node = queue.poll();
                System.out.println(node.val);//处理数据
                if(node.left!=null){
                    queue.offer(node.left);
                }
                if(node.right!=null){
                    queue.offer(node.right);
                }
            }
        }
}
DFS(深度优先搜索)

深度优先搜索分为前序遍历、中序遍历、后续遍历 也就是root节点的访问顺序

递归

DFS推荐使用递归实现,代码比较简单易懂

public static void DFS(TreeNode root){
        if(root==null){
            return;
        }
        System.out.println(root.val);
        //前序遍历在这里处理数据
        DFS(root.left);
        //中序遍历在这里处理数据
        DFS(root.right);
        //后续遍历在这里处理数据
}
非递归

递归主要就是运用了方法的调用栈,非递归的话我们只要自己实现一个栈来保存数据即可

  1. 前序遍历
//前序遍历
public static void DFSStackPreOrder(TreeNode root){
        //root left right的遍历顺序
        if(root==null){
            return;
        }
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode node = stack.pop();//root先访问到,所以先出栈
            if(node.right!=null){//right是最后访问到的,所以先入栈
                stack.push(node.right);
            }
            if(node.left!=null){
                stack.push(node.left);
            }
            System.out.println(node.val);//处理数据
        }
}
  1. 中序遍历
public static void DFSStackInOrder(TreeNode root){
        //left root  right的遍历顺序
        Stack<TreeNode> stack = new Stack<>();
        while (!stack.isEmpty()||root!=null){
            if(root!=null){
            //当前子树左节点不为空的话,
            //先将左节点入栈
               stack.push(root);
               root = root.left;
            }else{
            //当前子树左节点为空,
            //说明遍历到了最左边了,
            //要开始遍历子节点的有右子树了
               root = stack.pop();//出栈,拿到的是子节点的最左边
               System.out.println(root.val);//处理数据
               root = root.right;//把root设置成右子树,开始遍历右子树
            }
        }
}
  1. 后续遍历
public static void DFSStackPostOrder(TreeNode root){
        //left right  root的遍历顺序
        if(root==null){
            return;
        }
        //后续遍历需要借助一个链表来先保存结果
        List<Integer> result = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            //root是最后访问到的,
            // 所以需要每次都在链表头节点插入,
            // 这样最后root就会排在链表尾部
            result.add(0,root.val);
            if(root.left!=null){
                stack.push(root.left);
            }
            if(root.right!=null){
                stack.push(root.right);
            }
            root = stack.pop();
        }
        //到这里,链表里的数据就是最后结果了
        System.out.println(result);
}
辅助的代码,生成树
public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int x) {
        val = x;
    }

    public static TreeNode generate(Integer[] a) {
        Queue<TreeNode> queue = new ArrayDeque<>();
        TreeNode root = new TreeNode(a[0]);
        queue.add(root);
        for (int i =1;i<a.length;i+=2) {
            TreeNode treeNode = queue.remove();
            if (a[i] != null) {
                treeNode.left = new TreeNode(a[i]);
                queue.add(treeNode.left);
            }
            if (i + 1 < a.length && a[i + 1] != null) {
                treeNode.right = new TreeNode(a[i + 1]);
                queue.add(treeNode.right);
            }
        }
        return root;
    }
}

例如这样的树

   3
  / \
 9  20
   /  \
  15   7

构造树

TreeNode root = TreeNode.generate(new Integer[{3,9,20,null,null,15,7});