有向图

栏目: 数据库 · 发布时间: 7年前

内容简介:《Algorithm》(Sedgewick)笔记:有向图一幅有称一条有向边由第一个顶点

《Algorithm》(Sedgewick)笔记:有向图

术语

一幅有 方向性的图 (或 有向图 )是由一组 顶点 和一组 有方向的边 组成的,每条有方向的边都连接着有序的一对顶点。

称一条有向边由第一个顶点 指出指向 第二个顶点。

一个顶点的 出度 为由该顶点指出的边的总数,一个顶点的 入度 为指向该顶点的边的总数。

一条有向边的第一个顶点成为它的 ,第二个顶点称为它的

在一幅有向图中, 有向路径 由一系列顶点组成,对于其中的每个顶点都存在一条有向边从它指向序列中的下一个顶点。

有向环为一条至少含有一条边且起点和终点相同的有向路径。 简单有向环 是一条除了起点和终点必须相同之外,不含有重复的顶点和边的环。

路径或环的 长度 即为其中所包含的边数。

图示

有向图

表示

使用邻接表表示

有向图

数据类型

public class DiGraph {
    private int V;
    private int E;
    private Bag<Integer>[] adj;

    public DiGraph(int V) {
        this.V = V;
        this.E = 0;
        adj = (Bag<Integer>[]) new Bag[V];
        for (int v = 0; v < V; v++)
            adj[v] = new Bag<>();
    }
    //输入初始化构造函数
    public DiGraph() {
        Scanner in = new Scanner(System.in);
        V = in.nextInt();
        adj = (Bag<Integer>[]) new Bag[V];
        for (int v = 0; v < V; v++)
            adj[v] = new Bag<Integer>();
        int e = in.nextInt();
        for (int i = 0; i < e; i++) {
            int v = in.nextInt();
            int w = in.nextInt();
            addEdge(v, w);
        }
    }
    public int V() {
        return V;
    }
    public int E() {
        return E;
    }
    public void addEdge(int v, int w) {
        adj[v].add(w);
        E++;
    }
    public Iterable<Integer> adj(int v) {
        return adj[v];
    }
    public DiGraph reverse() {
        DiGraph R = new DiGraph(V);
        for (int v = 0; v < V; v++)
            for (int w : adj[v])
                R.addEdge(w, v);
        return R;
    }
    public String toString() {
        String s = V + " vertices, " + E + " edges\n";
        for (int v = 0; v < V; v++) {
            s += v + ": ";
            for (int w : this.adj[v])
                s += w + " ";
            s += "\n";
        }
        return s;
    }
}

源代码

https://github.com/XutongLi/Algorithm-Learn/tree/master/src/S4_Graphs/S4_2_Directed_Graph/S4_2_2_DiGraph

有向图的深度优先搜索

图示

有向图

使用

使用DFS可以检测有向图的可达性,即解决“是否存在一条从s到达给定顶点v的有向路径”或“是否存在一条从结合中的任意顶点到达给定顶点v的有向路径”等问题。

递归代码

public class DiDFS {
    private boolean[] marked;
      //单源
    public DiDFS(DiGraph G, int s) {
        marked = new boolean[G.V()];
        dfs(G, s);
    }
      //多源
    public DiDFS(DiGraph G, Iterable<Integer> sources) {
        marked = new boolean[G.V()];
        for (int s : sources)
            if (!marked[s]) dfs(G, s);
    }
    private void dfs(DiGraph G, int v) {
        marked[v] = true;
        for (int w : G.adj(v))
            if (!marked[w]) dfs(G, w);
    }
    public boolean marked(int v) {
        return marked[v];
    }
}

非递归代码

public class DiDFS_Nonrecur {
    private boolean[] marked;

    public DiDFS_Nonrecur(DiGraph G, int s) {
        marked = new boolean[G.V()];
        Iterator<Integer>[] adj = (Iterator<Integer>[]) new Iterator[G.V()];
        for (int v = 0; v < G.V(); v++) {
            adj[v] = G.adj(v).iterator();
        }
        Stack<Integer> stack = new Stack<>();
        marked[s] = true;
        stack.push(s);
        while (!stack.isEmpty()) {
            int v = stack.peek();
            if (adj[v].hasNext()) {
                int w = adj[v].next();
                if (!marked[w]) {
                    marked[w] = true;
                    stack.push(w);
                }
            }
            else {
                stack.pop();
            }
        }
    }

    public DiDFS_Nonrecur(DiGraph G,Iterable<Integer> sources) {
        marked = new boolean[G.V()];
        Iterator<Integer>[] adj = (Iterator<Integer>[]) new Iterator[G.V()];
        for (int v = 0; v < G.V(); v++) {
            adj[v] = G.adj(v).iterator();
        }
        for (int s : sources) {
            Stack<Integer> stack = new Stack<>();
            marked[s] = true;
            stack.push(s);
            while (!stack.isEmpty()) {
                int v = stack.peek();
                if (adj[v].hasNext()) {
                    int w = adj[v].next();
                    if (!marked[w]) {
                        marked[w] = true;
                        stack.push(w);
                    }
                }
                else {
                    stack.pop();
                }
            }
        }
    }

    public boolean marked(int v) {
        return marked[v];
    }
}

源代码

https://github.com/XutongLi/Algorithm-Learn/tree/master/src/S4_Graphs/S4_2_Directed_Graph/S4_2_3_DiDFS

深度优先搜索路径

代码

public class DiDFSPath {
    private boolean[] marked;
    private int[] edgeTo;
    private int s;

    public DiDFSPath(DiGraph G, int s) {
        marked = new boolean[G.V()];
        edgeTo = new int[G.V()];
        this.s = s;
        dfs(G, s);
    }
    private void dfs(DiGraph G, int v) {
        marked[v] = true;
        for (int w : G.adj(v)) {
            if (!marked[w]) {
                edgeTo[w] = v;
                dfs(G, w);
            }
        }
    }
    public boolean hasPathTo(int v) {
        return marked[v];
    }
    public Iterable<Integer> pathTo(int v) {
        if (!hasPathTo(v))   return null;
        Stack<Integer> stack = new Stack<>();
        for (int x = v; x != s; x = edgeTo[x]) {
            stack.push(x);
        }
        stack.push(s);
        Queue<Integer> queue = new LinkedList<>();
        while (!stack.isEmpty()) {
            queue.offer(stack.pop());
        }
        return queue;
    }
}

源代码

https://github.com/XutongLi/Algorithm-Learn/tree/master/src/S4_Graphs/S4_2_Directed_Graph/S4_2_3_DiDFSPath

广度优先搜索路径

代码

public class DiBFSPath {
    private final int INFINITY = Integer.MAX_VALUE;
    private boolean[] marked;
    private int [] edgeTo;
    private int[] distTo;
    private int s;

    public DiBFSPath(DiGraph G, int s) {
        marked = new boolean[G.V()];
        edgeTo = new int[G.V()];
        distTo = new int[G.V()];
        this.s = s;
        for (int v = 0; v < G.V(); v++) {
            distTo[v] = INFINITY;
        }
        bfs(G, s);
    }
    private void bfs(DiGraph G, int s) {
        Queue<Integer> q = new LinkedList<>();
        q.offer(s);
        marked[s] = true;
        distTo[s] = 0;
        while (!q.isEmpty()) {
            int v = q.poll();
            for (int w : G.adj(v)) {
                if (!marked[w]) {
                    marked[w] = true;
                    distTo[w] = distTo[v] + 1;
                    edgeTo[w] = v;
                    q.offer(w);
                }
            }
        }
    }
    public boolean hasPathTo(int v) {
        return marked[v];
    }
    public int distTo(int v) {
        return distTo[v];
    }
    public Iterable<Integer> pathTo(int v) {
        if (!hasPathTo(v))   return null;
        Stack<Integer> stack = new Stack<>();
        for (int x = v; x != s; x = edgeTo[x]) {
            stack.push(x);
        }
        stack.push(s);
        Queue<Integer> queue = new LinkedList<>();
        while (!stack.isEmpty()) {
            queue.offer(stack.pop());
        }
        return queue;
    }
}

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

精通 CSS(第3版)

精通 CSS(第3版)

[英]安迪•巴德 - Andy Budd、[瑞典]埃米尔•比约克隆德 - Emil Björklund / 李松峰 / 人民邮电出版社 / 2019-2 / 99

本书是CSS设计经典图书升级版,结合CSS近年来的发展,尤其是CSS3和HTML5的特性,对内容进行了全面改写。本书介绍了涉及字体、网页布局、响应式Web设计、表单、动画等方面的实用技巧,并讨论了如何实现稳健、灵活、无障碍访问的Web设计,以及在技术层面如何实现跨浏览器方案和后备方案。本书还介绍了一些鲜为人知的高级技巧,让你的Web设计脱颖而出。一起来看看 《精通 CSS(第3版)》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

随机密码生成器
随机密码生成器

多种字符组合密码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具