dfs和bfs遍历图

3、遍历

  1. bfs : Breadth first search

思路:

二叉树的层序遍历很像,应用队列,一层一层的遍历

注意在图中,下一层指的是 此节点一步能到达的位置

不过这里变成了遍历顶点的 outEdges 依次入队,不过当图有环的时候可能重复出现斯循环,所以我们用set来去重!

  • 代码
 //遍历图,使用BFS算法!

    public void bfs(V value) {
        Vertex<V, E> vertex = vertices.get(value);  //遍历的起点
        if (vertex == null) return;
        Queue<Vertex<V, E>> queue = new LinkedList<>();     //使用队列,java中队列由双向链表实现
        Set<Vertex<V, E>> set = new HashSet<>();        //用set去重,怎么去?入队的同时在set中加上
        queue.offer(vertex);
        set.add(vertex);
        while (!queue.isEmpty()) {
            Vertex<V, E> poll = queue.poll();
            System.out.println(poll.value);
            for (Edge<V, E> outEdge : poll.outEdges) {  //outEdges的终点就是下一层节点
                if (set.contains(outEdge.to)) continue;
                queue.offer(outEdge.to);
                set.add(outEdge.to);
            }
        }
    }
  1. DFS : depth frist search
  • 递归实现

思路:我们在想递归的时候千万不要往深了想,其实还是很简单的

  • 代码:
//深度优先搜素,相当于前序遍历!
    @Override
    public void dfs(V begin) {
        Vertex<V, E> vertex = vertices.get(begin);
        if (vertex == null)
            return;
        dfs(vertex, new HashSet<>());
    }

    private void dfs(Vertex<V,E> vertex, Set<Vertex<V, E>> set) {
        if (vertex == null)
            return;
        System.out.println(vertex.value);
        set.add(vertex);
        for (Edge<V, E> outEdge : vertex.outEdges) {
            if (set.contains(outEdge.to)) continue;
            dfs(outEdge.to, set);
        }
    }

又要使用set去重和上面的去重思路差不多!

总结:如何理解循环中的递归:

如果是上述图我们从 节点 1 开始遍历:上来就会进入for循环,遍历了

dfs(3) 、 dfs(5) 、dfs(2) 、dfs(0)

进入dfs(3) 又是进行深度优先搜索,遍历 7 ,遍历完3,才会遍历 dfs(5) ···

就这么理解就行!

3、DFS非递归实现

就是先序遍历,选一条变向下走到极致在回头!

所有的递归都能转化成迭代,不过有的很难

为什么呢?

因为递归就是函数JVM压栈出栈的过程,而我们数据结构中的栈也是这个特点,所以很多复杂的递归都能使用栈和迭代来实现!

代码:主要是想到要用到栈,结合栈先进后出的特点进行深度思考!

 public void dfs(V begin, Visitor<V, E> visitor) {
        if (visitor == null) return;
        Vertex<V, E> vertex = vertices.get(begin);
        if (vertex == null) {
            return;
        }
        Stack<Vertex<V, E>> stack = new Stack<>();
        Set<Vertex<V, E>> visited = new HashSet<>();
        stack.push(vertex);
        if (visitor.visit(vertex.value)) return;
        visited.add(vertex);
        while (!stack.isEmpty()) {
            Vertex<V, E> pop = stack.pop();
            for(Edge<V, E> edge : pop.outEdges) {
                if (visited.contains(edge.to)) continue;
                stack.push(pop);
                stack.push(edge.to);
                if (visitor.visit(edge.to.value)) return;
                visited.add(edge.to);
                break;	//这个break才是最关键的,我们只会选择一条边向下钻
            }
        }
    }


总结:set是无序的所以不知道先遍历那条边,为什么要 把from 和 to都放进去在Break,我们每次只访问to节点的值···

posted @ 2020-07-15 18:43  贝加尔湖畔╭  阅读(335)  评论(0编辑  收藏  举报