【算法4】4.1.无向图

无向图

无向图 API:

public abstract Graph {
    Graph(int V); // 创建一个含有 V 个顶点的图
    Graph(In in); // 从标准输入读取一幅图
    int V(); // 顶点数
    int E(); // 边数
    void addEdge(int v, int w); // 添加一条边 v-w
    Iterable<Integer> adj(int v); // 返回所有相邻顶点
    String toString()
}

图的三种表示方法:

  • 邻接矩阵:VxV 布尔矩阵(消耗空间大)
  • 边的数组:Edge 数组(获取顶点的相邻顶点需要遍历所有边)
  • 邻接表数组:一个以顶点为索引的数组,其值是顶点的相邻顶点列表(适合大型稀疏图)

图搜索算法

图搜索算法 API:

public class Search {
    Search(Graph G, int s); // s 表示起点
    boolean marked(int v); // s 和 v 是否连通
    int count(); // 和 s 连通的顶点数
}

深度优先搜索算法用一个递归方法来遍历所有与起点连通的顶点,当方法访问顶点时:

  1. 标记顶点
  2. 递归访问未被标记的相邻顶点
// 深度优先搜索算法
public class DepthFirstSearch {
    private boolean[] marked;
    private int count;

    // s 表示起点
    public DepthFirstSearch(Graph G, int s) {
        marked = new boolean[G.V()];
        dfs(G, s);
    }

    // 深度优先搜索算法
    private void dfs(Graph G, int v) {
        marked[v] = true;
        count++;
        for (int w : G.adj(v)) {
            if (!marked[w]) {
                dfs(G, w);
            }
        }
    }

    // 顶点 v 是否与起点 s 连通
    public boolean marked(int v) {
        return marked[v];
    }

    // 与 s 连通的顶点数量
    public int count() {
        return count;
    }
}

单点路径

路径 API:

public class Paths {
    Paths(Graph G, int s);
    boolean hasPathTo(int v);
    Iterable<Integer> pathTo(int v);
}

基于深度优先搜索实现的单点路径:

// 路径 API
// 基于深度优先搜索算法实现
public class DepthFirstPaths {
    private boolean[] marked;
    private int[] pathTo;
    private final int s;
    
    // 找出所有与起点 s 连通的顶点到 s 的路径
    public DepthFirstPaths(Graph G, int s) {
        this.marked = new boolean[G.V()];
        this.pathTo = new int[G.V()];
        this.s = s;
        dfs(G, s);
    }

    private void dfs(Graph G, int v) {
        marked[v] = true;
        for (int w : G.adj(v)) {
            if (!marked[w]) {
                pathTo[w] = v;
                dfs(G, w);
            }
        }
    }

    // 起点 s 到顶点 v 是否存在一条路径
    public boolean hasPathTo(int v) {
        return marked[v];
    }

    // 如果起点 s 到顶点 v 存在路径,返回该路径
    // 否则,返回 null
    public Iterable<Integer> pathTo(int v) {
        if (!hasPathTo(v)) {
            return null;
        }
        Deque<Integer> deque = new ArrayDeque<>();
        while (v != s) {
            deque.push(v);
            v = pathTo[v];
        }
        deque.push(s);
        return CollectionUtils.dequeToStack(deque);
    }
}

基于广度优先搜索实现的单点最短路径:

// 路径 API
// 基于广度优先搜索实现
public class BreadthFirstPaths {
    private boolean[] marked;
    private int[] pathTo;
    private final int s;

    // 找出所有与起点 s 连通的顶点到 s 的最短路径
    public BreadthFirstPaths(Graph G, int s) {
        this.marked = new boolean[G.V()];
        this.pathTo = new int[G.V()];
        this.s = s;
        bfs(G, s);
    }

    // 广度优先搜索
    private void bfs(Graph G, int s) {
        Queue<Integer> queue = new ArrayDeque<>();
        marked[s] = true;
        pathTo[s] = s;
        queue.add(s);
        while (!queue.isEmpty()) {
            int v = queue.remove();
            for (int w : G.adj(v)) {
                if (!marked[w]) {
                    marked[w] = true;
                    pathTo[w] = v;
                    queue.add(w);
                }
            }
        }
    }

    // 是否存在从起点 s 到顶点 v 的路径
    public boolean hasPathTo(int v) {
        return marked[v];
    }

    // 如果起点 s 到顶点 v 存在路径,返回最短的一条
    // 否则,返回 null
    public Iterable<Integer> pathTo(int v) {
        if (!hasPathTo(v)) {
            return null;
        }
        Deque<Integer> deque = new ArrayDeque<>();
        while (v != s) {
            deque.push(v);
            v = pathTo[v];
        }
        deque.push(s);
        return CollectionUtils.dequeToStack(deque);
    }
}
posted @ 2022-06-01 23:39  廖子博  阅读(41)  评论(0编辑  收藏  举报