深度优先搜索(DFS)

来源:互联网 发布:bp神经网络算法 matlab 编辑:程序博客网 时间:2024/06/06 09:55

一、概述

深度优先搜索英文全称为(Depth-First search),简称DFS。为图的一种遍历方式,所采用的策略可概况为优先选取最后一个被访问到的顶点的邻居。于是,以顶点s为基点的DFS搜索,将首先访问顶点s;再从s所有尚未访问到的邻居中任取其一,并以之为基点,递归地执行DFS搜索。故各顶点被访问到的次序,类似于树的先序遍历,当访问到该顶点没有了邻居顶点,于是就回溯访问,而各顶点被访问完毕的次序,则类似于树的后序遍历。

二、实现

从图中选取一个顶点,作为第一次DFS 的起始顶点,从该顶点中的邻居顶点中任选其一,作为基点,再从该顶点中的邻居顶点中任选其一,依次递归,直到到达最后一个没有邻居顶点的顶点。然后返回上一个顶点,选取它另外一个邻居顶点,然后以此类推。直到所有图中所有顶点被访问完毕。

下图来表示遍历过程

DFS树中v是否为u的祖先,若是(v,u)为前向边(forward edge),否则为后向边(backward edge), 若二者来自相互独立的两个分支,则为跨边(cross edge)

这里写图片描述
这里写图片描述
图(u)表示选取D为起始顶点

三、代码

下列代码是Java编写的,用一个整型数值来代表一个顶点

创建图的操作接口

package cn.adt.dfs.graph;import java.util.Set;/** * Created by YangT on 2017-8-11. * 图的顶点用整形来表示 */public interface Graph {    boolean addVertex(Integer v);    Double addEdge(Integer from,Integer to);    boolean addEdge(Integer from,Integer to,Double weigth);    boolean removeVertex(Integer v);    boolean removeEdge(Integer from,Integer to);    Set<Integer> getVertices();    Set<Integer> getNeighbors(Integer v);    int size();}

一个有向图实例

package cn.adt.dfs.graph;import java.util.HashMap;import java.util.HashSet;import java.util.Map;import java.util.Set;import cn.adt.dfs.graph.Graph;/** * Created by YangT on 2017-8-11. * 有向图 */public class DirectedGraph implements Graph {    private Map<Integer,Set<Integer>> vertexMap = new HashMap<>();    /**     * map的键存放顶点,值存放与该顶点相连的顶点     */    @Override    public boolean addVertex(Integer v) {        vertexMap.put(v, new HashSet<Integer>());        return true;    }    @Override    public Double addEdge(Integer from, Integer to) {        if(!vertexMap.containsKey(from)) return -1d;        if(!vertexMap.containsKey(to)) return -1d;        vertexMap.get(from).add(to);        return 0d;    }    @Override    public boolean addEdge(Integer from, Integer to, Double weigth) {        //当前不支持带权图        return false;    }    @Override    public boolean removeVertex(Integer v) {        if(!vertexMap.containsKey(v)) return false;        vertexMap.remove(v);        return true;    }    @Override    public boolean removeEdge(Integer from, Integer to) {        if(!vertexMap.containsKey(from)) return false;        if(!vertexMap.containsKey(to)) return false;        vertexMap.get(from).remove(to);        return true;    }    @Override    public Set<Integer> getVertices() {        return vertexMap.keySet();    }    @Override    public Set<Integer> getNeighbors(Integer v) {        return vertexMap.get(v);    }    @Override    public int size() {        return vertexMap.size();    }}

DFS实现

package cn.graph.dfs;import java.util.HashMap;import java.util.HashSet;import java.util.LinkedList;import java.util.List;import java.util.Map;import java.util.Set;import java.util.Stack;import cn.adt.dfs.graph.Graph;/** * Created by YangT on 2017-8-11. * 图的顶点用整形来表示 */public class DFS {    private Graph graph;    //创建一个时间,来表示整个DFS时间,各顶点的状态    private Integer clock = 0;    //创建各顶点入栈时间map,也就是被发现时间    private Map<Integer,Integer> ftimeMap = new HashMap<>();    //创建各顶点出栈时间map,也就是回溯该顶点时间    private Map<Integer,Integer> dtimeMap = new HashMap<>();    private List<Integer> path = new LinkedList<>();    private Set<Integer> visited = new HashSet<>();    private Stack<Integer> stack = new Stack<>();    public DFS(Graph graph){        this.graph = graph;    }    //搜索    public void search(Integer source){        if(source == null || !graph.getVertices().contains(source))            return;        path.add(source);        visited.add(source);        stack.push(source);        ftimeMap.put(source, ++clock);        for(Integer neighbor : graph.getNeighbors(source)){            //判断该顶点是否已被访问            if(visited.contains(neighbor)) continue;            search(neighbor);        }        Integer v = stack.pop();        dtimeMap.put(v, ++clock);    }    //显示顶点被发现和回溯完成的时间    public void showTime(){        Set<Integer> keys = ftimeMap.keySet();        for (Integer key : keys) {            System.out.print("入栈时间 " + key + ":" + ftimeMap.get(key) + " ");        }        System.out.println(" ");        Set<Integer> dkeys = dtimeMap.keySet();        for (Integer key : dkeys) {            System.out.print("出栈时间 " + key + ":" + dtimeMap.get(key) + " ");        }    }    //检查所有顶点是否都已访问到    public boolean check(){        if(graph.size() != visited.size()){            return false;        }        return true;    }    /**     * 获取访问顺序     */    public List<Integer> getPath(Integer source){        if(source == null || !graph.getVertices().contains(source))            return null;        search(source);         /**         * DFS从一个顶点开始,不可能访问到所有顶点,因此要另取一个顶点,做第二次DFS         */        while(!check()){            for (Integer v : graph.getVertices()) {                if(!visited.contains(v)){                    search(v);                }            }        }        return path;    }}

测试代码

package cn.test;import java.util.List;import cn.adt.dfs.graph.DirectedGraph;import cn.adt.dfs.graph.Graph;import cn.graph.dfs.DFS;/** * Created by YangT on 2017-8-11. * 图的顶点用整形来表示 */public class DFSTest {    public static void main(String[] args) {        /**         * 创建一个有向图,顶点用整型数值来表示         */        Graph g = new DirectedGraph();        for (int i = 1; i < 8; i++) {            g.addVertex(i);        }        g.addEdge(1, 2);        g.addEdge(2, 3);        g.addEdge(1, 3);        g.addEdge(4, 1);        g.addEdge(1, 6);        g.addEdge(4, 5);        g.addEdge(5, 6);        g.addEdge(7, 1);        g.addEdge(7, 3);        g.addEdge(6, 7);        DFS dfs = new DFS(g);        /**         * 从顶点1开始dfs         * 输出各顶点的访问顺序         * 调用showTime方法,输出各顶点的被发现和回溯完成访问该顶点时间         */        List<Integer> paths = dfs.getPath(1);        for (Integer v : paths) {            System.out.print(v + " ");        }        System.out.println(" ");        dfs.showTime();    }}

图的构造顶点由整型来代替。测试类创建的图仿照上面图片建立

代码不是很完善,希望能指正。如有错误,希望能指正,谢谢。

参考书籍:数据结构第三版 作者:邓俊辉

参考代码:
https://github.com/sherxon/AlgoDS/blob/master/src/algo/graph/DFS.java

原创粉丝点击