欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

图的深度优先搜索和广度优先搜索

程序员文章站 2022-07-13 08:34:54
...

一、图

  在计算机科学中,一个图就是一些顶点的集合,这些顶点通过一系列边结对(连接)。顶点用圆圈表示,边就是这些圆圈之间的连线。顶点之间通过边连接。

基本概念

  阶(Order):图G中点集V的大小称作图G的阶。

  度(Degree):一个顶点的度是指与该顶点相关联的边的条数,顶点v的度记作d(v)。

  入度(In-degree)和出度(Out-degree):对于有向图来说,一个顶点的度可细分为入度和出度。一个顶点的入度是指与其关联的各边之中,以其为终点的边数;出度则是相对的概念,指以该顶点为起点的边数。

  子图(Sub-Graph):当图G'=(V',E')其中V‘包含于V,E’包含于E,则G'称作图G=(V,E)的子图。每个图都是本身的子图。

  路径(Path):从u到v的一条路径是指一个序列v0,e1,v1,e2,v2,...ek,vk,其中ei的顶点为vi及vi - 1,k称作路径的长度。如果它的起止顶点相同,该路径是“闭”的,反之,则称为“开”的。一条路径称为一简单路径(simple path),如果路径中除起始与终止顶点可以重合外,所有顶点两两不等。

二元组的定义

  图G是一个有序二元组(V,E),其中V称为顶集(Vertices Set),E称为边集(Edges set),E与V不相交。它们亦可写成V(G)和E(G)。

  E的元素都是二元组,用(x,y)表示,其中x,y∈V。 

三元组的定义

  图G是指一个三元组(V,E,I),其中V称为顶集,E称为边集,E与V不相交;I称为关联函数,I将E中的每一个元素映射到(v,v)。

  如果e被映射到(u,v),那么称边e连接顶点u,v,而u,v则称作e的端点,u,v此时关于e相邻。同时,若两条边i,j有一个公共顶点u,则称i,j关于u相邻。

图的存储-邻接矩阵

图的深度优先搜索和广度优先搜索

图的存储-邻接表

图的深度优先搜索和广度优先搜索

public class Graph {
    //顶点数目
    private int v;
    //边的数目
    private int e;
    //邻接表
    private Queue<Integer>[] adj;
    public Graph(int v) {
        //初始化定点数量
        this.v = v;
        //初始化边的数量
        this.e = 0;
        //初始化邻接表
        this.adj = new Queue[v];
        for(int i = 0; i < adj.length; i++) {
            adj[i] = new LinkedList<>();
        }
    }
    //获取定点数目
    public int getV() {
        return v;
    }
    //获取边数目
    public int getE() {
        return e;
    }
    //向图中添加一条边v-w
    public void addEdge(int v, int w) {
        //在无向图中,边是没有方向的,所以该边既可以说是v到w的边,也可以说是从w到v的边,因此,让v出现在w表中并让w出现在v表中
        adj[v].offer(w);
        adj[w].offer(v);
        e++;
    }
    //获取和定点v相邻的所有定点
    public Queue<Integer> adj(int v) {
        return adj[v];
    }
}

二、图的深度优先搜索

图的深度优先搜索和广度优先搜索

class DepthFirstSearch {
    //索引代表顶点,表示当前顶点是否已经被搜索
    private boolean[] marked;
    //记录有多少个顶点和s顶点相通
    private int count;
    //构造深度优先搜索对象,使用深度优先搜索找出G图中s顶点的所有相通顶点
    DepthFirstSearch(Graph graph, int s) {
        //初始化mark数组
        this.marked = new boolean[graph.getV()];
        //初始化定点s相通的顶点的数量
        this.count = 0;
        dfs(graph, s);
    }
    //使用深度优先搜索找出G图中v顶点的所有相通顶点
    private void dfs(Graph graph, int v) {
        //把v顶点标志为已搜索
        marked[v] = true;
        for(Integer w : graph.adj(v)) {
            //判断当前顶点有没有被搜索,如果没有被搜索,则递归调用dfs方法进行深度搜索
            if(!marked[w]) {
                dfs(graph, w);
            }
        }
        //相通顶点数+1
        count++;
    }
    //判断w顶点是否与s顶点相通
    public boolean marked(int w) {
        return marked[w];
    }
    //获取与顶点s相通的所有定点总数
    public int count() {
        return count;
    }
    //主类
    public static void main(String args[]) {
        //准备graph对象
        Graph graph = new Graph(13);
        graph.addEdge(0, 5);
        graph.addEdge(0, 1);
        graph.addEdge(0, 2);
        graph.addEdge(0, 6);
        graph.addEdge(5, 3);
        graph.addEdge(5, 4);
        graph.addEdge(3, 4);
        graph.addEdge(4, 6);
        graph.addEdge(7, 8);
        graph.addEdge(9, 10);
        graph.addEdge(9, 11);
        graph.addEdge(9, 12);
        graph.addEdge(11, 12);
        //准备深度搜索对象
        DepthFirstSearch depthFirstSearch = new DepthFirstSearch(graph, 0);
        //测试与某个顶点相通顶点数量
        System.out.println("与起点0相通的顶点的数量为:" + depthFirstSearch.count());
        //测试某个顶点与起点是否相同
        System.out.println("顶点0是否与顶点5相通:" + depthFirstSearch.marked(5));
        System.out.println("顶点0是否与顶点7相通:" + depthFirstSearch.marked(7));
    }
}

图的深度优先搜索和广度优先搜索

三、图的广度优先搜索

图的深度优先搜索和广度优先搜索

class BreadthFirstSearch {
    //索引代表顶点,值表示当前顶点是否已经被搜索
    private boolean[] marked;
    //记录多少个顶点与s顶点相通
    private int count;
    //用来存储搜索邻接表的点
    private Queue<Integer> waitSearch;
    //构造广度优先搜索对象,使用广度优先搜索出G图中的s顶点的所有相邻顶点
    BreadthFirstSearch(Graph graph, int s) {
        this.marked = new boolean[graph.getV()];
        this.count = 0;
        this.waitSearch = new LinkedList<>();
        bfs(graph, s);
    }
    //使用广度优先搜索出G图中v顶点的所有相邻顶点
    private void bfs(Graph graph, int v) {
        //把当前顶点v标志为已搜索
        marked[v] = true;
        //让顶点v进入队列,带搜索
        waitSearch.offer(v);
        //通过循环,如果队列不为空,则从队列中弹出一个带搜索的顶点进行搜索
        while(!waitSearch.isEmpty()) {
            //弹出一个待搜索顶点
            Integer wait = waitSearch.poll();
            //遍历wait顶点的邻接表
            for(Integer w : graph.adj(wait)) {
                if(!marked[w]) {
                    bfs(graph, w);
                }
            }
        }
        //让相通的节点+1
        count++;
    }
    //判断w顶点是否与s顶点相通
    public boolean marked(int w) {
        return marked[w];
    }
    //获取与顶点s相通的所有顶点总数
    public int count() {
        return count;
    }
    //主类
    public static void main(String args[]) {
        //准备graph对象
        Graph graph = new Graph(13);
        graph.addEdge(0, 5);
        graph.addEdge(0, 1);
        graph.addEdge(0, 2);
        graph.addEdge(0, 6);
        graph.addEdge(5, 3);
        graph.addEdge(5, 4);
        graph.addEdge(3, 4);
        graph.addEdge(4, 6);
        graph.addEdge(7, 8);
        graph.addEdge(9, 10);
        graph.addEdge(9, 11);
        graph.addEdge(9, 12);
        graph.addEdge(11, 12);
        //准备深度搜索对象
        BreadthFirstSearch breadthFirstSearch = new BreadthFirstSearch(graph, 0);
        //测试与某个顶点相通顶点数量
        System.out.println("与起点0相通的顶点的数量为:" + breadthFirstSearch.count());
        //测试某个顶点与起点是否相同
        System.out.println("顶点0是否与顶点5相通:" + breadthFirstSearch.marked(5));
        System.out.println("顶点0是否与顶点7相通:" + breadthFirstSearch.marked(7));
    }
}

图的深度优先搜索和广度优先搜索