算法和数据结构(18)图的相关算法2

图的相关算法2

有向图

​ 在有向图中,边是单向的,每条边所链接的两个顶点都是一个有序堆,它们的邻接性是单向的,许多应用(网络,任务调度,电话)的图都是天然的有向图;

定义:一副有方向性的图,是由一组顶点和一组有方向的边组成,每条有方向的边都连接着有序的一对顶点;

概念

1. 出度:由该顶点指出的边的总数
2. 入度:指向顶点的边的总数;

有向图的数据结构

public class Digraph {
    private final 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 i = 0; i < v; i++) {
            adj[i] = new Bag<Integer>();
        }
    }

    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 i = 0; i < this.V; i++) {
            for (int w : this.adj(i)) {
                R.addEdge(w, i);
            }
        }
        return R;
    }

有向图的可达性

问题:

  1. 单点可达性:给定一副有向图和一个起点s,回到是否存在一条从s到达给定顶点v的有向路径?
  2. 多点可达性:给定一副有向图和顶点集合,是否存在一条从集合中的任意顶点到达给定顶点v的有向路径?

其实这些问题比相应的无向图算法的轨迹稍稍简单些,因为深度优先搜索本质上是一种适用于处理有向图的算法

深入理解下述代码有助于巩固对有向图中深度优先搜索的理解;

public class DirectedDFS {
    private boolean[] marked;
    public DirectedDFS(Digraph G, int s){
        marked = new boolean[G.V()];
        dfs(G,s);
    }

    public DirectedDFS(Digraph G , Iterable<Integer> sources) {
        this.marked = new boolean[G.V()];
        for (Integer s : sources) {
            if (!marked[s]){
                dfs(G,s);
            }
        }
    }

    private void dfs(Digraph g, int s) {
        marked[s] = true;
        for (int w : g.adj(s)) {
            if (!marked[w]) dfs(g,w);
        }
    }
    public boolean isReached(int v){
      return marked[v];
    }
}

最后只需要判断

DirectedDFS dd= new DirectedDFS(g,s);
dd.isReached(v);//判断是否到达顶点v;

环和有向图

在有向图任务调度问题中,可能存在这种情况,如 任务x必须在任务y之前完成,任务y必须在任务z之前完成,任务z又必须在任务x之前完成,这三个限制条件不可能被同时满足;即:如果一个有优先级的限制的问题中存在环,那么这个问题是无解的;故而需要解决下面这个问题:

有向环的检测。给定的有向图中是否存在有向环?

修改上述代码

public class DirectedDFS {
    private boolean[] marked;
    private int[] edgeTo;
    private Stack<Integer> cycle;
    private boolean[] onStack;

    public DirectedDFS(Digraph G, int s){
        onStack = new boolean[G.V()];
        marked = new boolean[G.V()];
        edgeTo = new int[G.V()];
        dfs(G,s);
    }

    public DirectedDFS(Digraph G , Iterable<Integer> sources) {
        this.marked = new boolean[G.V()];
        for (Integer s : sources) {
            if (!marked[s]){
                dfs(G,s);
            }
        }
    }

    private void dfs(Digraph g, int s) {
        marked[s] = true;
        onStack[s] = true;
        for (int w : g.adj(s)) {
            if (this.hasCycle()) return;
            else if (!marked[w]) {
                edgeTo[w] = s;
                dfs(g,w);
            }
            else if (onStack[w]) {
                cycle = new Stack<Integer>();
                for (int x = s; x != w ; x=edgeTo[x]) {
                    cycle.push(x);
                }
                cycle.push(s);
                cycle.push(w);
            }
            onStack[s]=false;
        }
    }

    private boolean hasCycle() {
        return cycle!=null;
    }

}

​ 在dfs中添加一个onStack[]来保存递归调用期间栈上的所有顶点,当它找到一个边上v-》w,且w在栈中,它就找到了一个有向环,环上的所有顶点可以通过edgeTo中的链接得到;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值