您的位置:首页 > 其它

有向图----有向环检测和拓扑排序

2017-12-21 00:00 681 查看
摘要: 一种应用广泛的模型是给定一组任务并安排它们的执行顺序,限制条件是这些任务的执行方法和起始时间。

上一篇:有向图的深度优先和广度优先遍历

优先级限制下的调度问题:给定一组需要完成的任务,以及一组关于任务完成的先后次序的优先级限制。在满足限制条件的前提下应该如何安排并完成所有任务?

拓扑排序:给定一幅有向图,将所有顶点排序,使得所有的有向边均从排在前面的元素指向排在后面的元素(或者说明无法做到这一点)。

优先级限制下不应该存在有向环,一个优先级限制的问题如果存在有向环,那么这个问题 肯定是无解的。

先来解决有向环检测问题

采用深度优先遍历来解决这个问题:用一个栈表示“当前”正在遍历的有向路径上的顶点。一旦找到一条有向边v->w,并且w已经存在于栈中,那么就找到了一个环;如果没有找到这条边,那么就是无环图。

实现:

public class DirectedCycle {
private boolean[] marked;
private int [] edgeTo;
private Stack<Integer> cycle;//有向环中所有顶点
private boolean[] onStack;//递归调用栈中所有顶点

public DirectedCycle(Digraph G) {
//略
}
//修改过的深度优先遍历
public void dfs(Digraph G,int v) {
onStack[v] = true;
marked[v] = true;
for(int w: G.adj(v)){
if(this.hasCycle())    return;    //检测出有环,算法停止
else if(!marked[v]) {
edgeTo[w] = v; dfs(G,w);
}
else if(onStack[w]) {    //如果为真,则说明形成了环,把环路经保存下来
cycle = new Stack<Integer>();
for(int x = v;x!= w;x=edgeTo[x])
cycle.push(x);
cycle.push(w);
cycle.push(v);
}
}
}

public boolean hasCycle() {  return cycle != null;  }
public Iterable<Integer> cycle(){  return cycle;  }
}

其实,将有向无环图的深度优先遍历的路径记录下来就是一种拓扑排序!遍历的顺序取决于数据结构的性质以及是在递归调用之前还是之后保存。一般有三种排列排序:

前序:在递归调用之前将顶点加入队列

后序:在递归调用之后将顶点加入队列

逆后序:在递归调用之后将顶点压入栈

基于深度优先搜索的顶点排序

public class DepthFirstOrder{
private boolean[] marked;
private Queue<Integer> pre;//所有顶点的前序排列
private Queue<Integer> post;//所有顶点的后序排列
private Stack<Integer> reversePost;//所有顶点的逆后序排列
//构造器
public DepthFirstOrder(Digraph G){
pre = new Queue<Integer>();
post = new Queue<Integer>();
revercePost = new Stack<Integer>();
marked = new boolean[G.V()];
for(int v = 0; v < G.V(); v++)
if(!marked[v]) dfs(G,v);
}
//深度优先遍历
private void dfs(Digraph G,int v) {
pre.enqueue(v);
marked[v] = true;
for(int w:G.adj(v))
if(!marked[w])
dfs(G,w);
post.enqueue(v);
reversePost.push(v);
}
//返回遍历结果
public Iterable<Integer> pre(){  return pre;  }
public Iterable<Integer> post(){  return post;  }
public Iterable<Integer> reversePost(){  return reversePost;  }
}

最后实现拓扑排序:

public class Tolpological {
private Iterable<Integer> order;
public Tolpological(Digraph G) {
DirectedCycle cyclefinder = new DirectedCycle(G);
//如果无有向环,则调用深度优先遍历,最后输出逆后序排列
if(!cyclefinder.hasCycle()) {
DepthFirstOrder dfs = new DepthFirstOrder(G);
order = dfs.reversePost();
}
}
public Iterable<Integer> order(){return order;}
}

一幅有向无环图的拓扑排序即为所有顶点的逆后序排序。

使用深度优先搜索对有向无环图进行拓扑排序需要的时间和V+E成正比。

下一篇:有向图的强连通分量问题
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息