简单易理解的BFS及DFS的Java实现

前言

原文链接:https://blog.csdn.net/Gene1994/article/details/85097507

DFS

注意区分(递归,回溯,DFS的区别)

递归是一种算法结构,回溯是一种算法思想。

回溯搜索是深度优先搜索(DFS)的一种,对于某一个搜索树来说(搜索树是起记录路径和状态判断的作用),回溯和DFS,其主要的区别是,回溯法在求解过程中不保留完整的树结构,而深度优先搜索则记下完整的搜索树。
在这里插入图片描述
上图可以看出DFS是如何工作的,使用DFS解决问题时最先想到的应该是递归和栈(Stack)

DFS是从起始顶点开始,递归访问其所有邻近节点,比如A节点是其第一个邻近节点,而B节点又是A的一个邻近节点,则DFS访问A节点后再访问B节点,如果B节点有未访问的邻近节点的话将继续访问其邻近节点,否则继续访问A的未访问邻近节点,当所有从A节点出去的路径都访问完之后,继续递归访问除A以外未被访问的邻近节点。

使用递归实现DFS遍历二叉树:(优先选择)

//DFS递归实现
public void DFSWithRecursion(TreeNode root) {
    if (root == null)
        return;
 
    //在这里处理遍历到的TreeNode节点
        
    if (root.left != null)
        DFSWithRecursion(root.left);
    if (root.right != null)
        DFSWithRecursion(root.right);
}

使用Stack实现DFS

//DFS的迭代实现版本(Stack)
public void DFSWithStack(TreeNode root) {
     if (root == null)
         return;
     Stack<TreeNode> stack = new Stack<>();
     stack.push(root);
 
     while (!stack.isEmpty()) {
         TreeNode treeNode = stack.pop();
 
         //在这里处理遍历到的TreeNode
             
         if (treeNode.right != null)
             stack.push(treeNode.right);
 
         if (treeNode.left != null)
             stack.push(treeNode.left);
     }
}

BFS(广度优先遍历,Breadth First Search)及DFS(深度优先遍历,Depth First Search)是遍历树或图的两种最常用的方法。本文简单的讲解在面对树或者图的问题时,使用BFS及DFS解答题目时的思路及实现。

BFS

在这里插入图片描述
根据上图就可以很清晰的理解出BFS的概念,即一层一层的遍历。在使用BFS解决问题的时候最先想到的方式应该是队列(Queue,FIFO)

其主要思想是从起始点开始,将其邻近的所有顶点都加到一个队列(FIFO)中去,然后标记下这些顶点离起始顶点的距离为1.最后将起始顶点标记为已访问,今后就不会再访问。然后再从队列中取出最先进队的顶点A,也取出其周边邻近节点,加入队列末尾,最后离开这个顶点A。依次下去,直到队列为空为止。从上面描述的过程我们知道每个顶点被访问的次数最多一次(已访问的节点不会再访问)。

代码:
首先定义二叉树:

//Definition for a binary tree node.
public class TreeNode {
  int val;
  TreeNode left;
  TreeNode right;
  TreeNode(int x) { val = x; }
}

使用队列实现BFS遍历二叉树:

//使用Queue实现BFS
public void BFSWithQueue(TreeNode root) {
    Queue<TreeNode> queue = new LinkedList<>();
    if (root != null)
        queue.add(root);
    while (!queue.isEmpty()) {
        TreeNode treeNode = queue.poll();
 
        //在这里处理遍历到的TreeNode节点
 
        if (treeNode.left != null)
            queue.add(treeNode.left);
        if (treeNode.right != null)
            queue.add(treeNode.right);
    }
}

以上三种方法都将数中每个节点遍历一遍,时间复杂度为O(N)。

N叉树

// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;
 
    public Node() {}
 
    public Node(int _val,List<Node> _children) {
        val = _val;
        children = _children;
    }
};

BFS及DFS只需将上述代码用for循环替代

图(graph)
图和树的最大区别在于图的下一个节点可能指向已访问过的节点。因此在使用BFS及DFS遍历时,应维护一个Set,Set中存放已被访问过的节点,在遍历时先判断节点未被访问过再遍历即可。

使用BFS举例如下:

//使用Queue实现BFS
public void BFSWithQueue(Node root) {
    Queue<Node> queue = new LinkedList<>();
    if (root != null)
        queue.add(root);
    Set<Node> visited = new HashSet<>();
    
    while (!queue.isEmpty()) {
        Node node = queue.poll();
        visited.add(node);
 
        //在这里处理遍历到的Node节点
 
        if (node.children != null) {
            for (Node child : node.children) {
                if (child != null && !visited.contains(child){
                    queue.add(child);
                }
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值