深度优先搜索、广度优先搜索

深度优先搜索:

英文是Depth First Search,简称为DFS。主要思路就是从图/树中一个顶点开始,沿着一条路一直走到底,然后从这条路尽头的节点回退到上一个节点,再从另一条路走到底。。。不断重复此过程,直到所有的节点都遍历完成。DFS的特点就是一条道走到黑,不撞南墙不回头。

DFS遍历下面的树,步骤是:

1、从根节点1开始遍历,它的子节点有2、3、4,先遍历节点2,再遍历节点2的子节点5,再遍历节点5的子节点9。如下图

2、走到底后要回退。从节点9回退到节点5,看下节点5是否有除节点9外的子节点。没有,则继续回退到节点2,再继续回退到节点1。节点1有除节点2外的子节点3、4,从节点3开始深度遍历。如下图

3、同理,从节点10往上回退到节点6,节点6没有除10外的子节点,再回退到节点3,节点3有除节点6外的子节点7,遍历7。如下图

4、从节点7往上回退到节点3,节点3没有除节点6、7外的子节点了,再往上回退到节点1。节点1还有除节点2、3外的子节点4,所以此时沿着节点4、8遍历。

综上,完整的遍历顺序如下

二叉树的DFS就是前序遍历。

DFS有递归和非递归两种实现方式。以二叉树的遍历讲解。

递归方式:

递归实现比较简单。从根节点开始,依次遍历根节点及其左右子树。遍历子树时,也是先遍历子树的根节点,再遍历其左右子树。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        preOrderWithList(root, list);
        return list;
    }

    private void preOrderWithList(TreeNode root, List<Integer> list) {
        if (root == null) {
            return;
        }
        list.add(root.val);
        if (root.left != null) {
            preOrderWithList(root.left, list);
        }
        if (root.right != null) {
            preOrderWithList(root.right, list);
        }
    }
}

递归方式,如果层级过深,有可能会栈溢出。实测不到10000层就栈溢出了,报StackOverflowError。可以考虑用尾递归来优化。

非递归方式:

非递归方式是有固定套路的,即建一个栈,先把根节点push到栈中。然后开启循环,循环中的操作是pop栈得到一个节点,访问其数据,然后把这个节点的右节点和左节点依次push到栈中。循环的退出条件是栈为空。

    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        preOrderWithList(root, list);
        return list;
    }

    private void preOrderWithList(TreeNode root, List<Integer> list) {
        if (root == null) {
            return;
        }

        Deque<TreeNode> stack = new ArrayDeque<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode node = stack.pop();
            list.add(node.val);
            if (node.right != null) {
                stack.push(node.right);
            }
            if (node.left != null) {
                stack.push(node.left);
            }
        }
    }

使用非递归方式不用担心栈溢出。

广度优先搜索:

英文是Breadth First Search,简称为BFS,适用于层序遍历和最短路径问题。

广度优先是有固定套路的,即建一个队列,先把根节点add到队列中。然后开启循环,循环中的操作是先算出队列的长度,假设为N,则remove N次。在每次remove拿到节点后,先把这个节点的左子节点和右子节点加到队列后,再remove拿下一个节点。循环的退出条件是队列为空。

posted on 2020-08-06 19:32  koushr  阅读(94)  评论(0编辑  收藏  举报

导航