有向图----有向环检测和拓扑排序
2017-12-21 00:00
681 查看
摘要: 一种应用广泛的模型是给定一组任务并安排它们的执行顺序,限制条件是这些任务的执行方法和起始时间。
上一篇:有向图的深度优先和广度优先遍历
优先级限制下的调度问题:给定一组需要完成的任务,以及一组关于任务完成的先后次序的优先级限制。在满足限制条件的前提下应该如何安排并完成所有任务?
拓扑排序:给定一幅有向图,将所有顶点排序,使得所有的有向边均从排在前面的元素指向排在后面的元素(或者说明无法做到这一点)。
优先级限制下不应该存在有向环,一个优先级限制的问题如果存在有向环,那么这个问题 肯定是无解的。
先来解决有向环检测问题:
采用深度优先遍历来解决这个问题:用一个栈表示“当前”正在遍历的有向路径上的顶点。一旦找到一条有向边v->w,并且w已经存在于栈中,那么就找到了一个环;如果没有找到这条边,那么就是无环图。
实现:
其实,将有向无环图的深度优先遍历的路径记录下来就是一种拓扑排序!遍历的顺序取决于数据结构的性质以及是在递归调用之前还是之后保存。一般有三种排列排序:
前序:在递归调用之前将顶点加入队列
后序:在递归调用之后将顶点加入队列
逆后序:在递归调用之后将顶点压入栈
基于深度优先搜索的顶点排序:
最后实现拓扑排序:
一幅有向无环图的拓扑排序即为所有顶点的逆后序排序。
使用深度优先搜索对有向无环图进行拓扑排序需要的时间和V+E成正比。
下一篇:有向图的强连通分量问题
上一篇:有向图的深度优先和广度优先遍历
优先级限制下的调度问题:给定一组需要完成的任务,以及一组关于任务完成的先后次序的优先级限制。在满足限制条件的前提下应该如何安排并完成所有任务?
拓扑排序:给定一幅有向图,将所有顶点排序,使得所有的有向边均从排在前面的元素指向排在后面的元素(或者说明无法做到这一点)。
优先级限制下不应该存在有向环,一个优先级限制的问题如果存在有向环,那么这个问题 肯定是无解的。
先来解决有向环检测问题:
采用深度优先遍历来解决这个问题:用一个栈表示“当前”正在遍历的有向路径上的顶点。一旦找到一条有向边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成正比。
下一篇:有向图的强连通分量问题
相关文章推荐
- c2java 第6篇 图的表示,最短路,圈检测和拓扑排序
- 算法细节系列(17):有向环检测&&拓扑排序
- LRJ系列 DFS实现拓扑排序(带有回路检测)
- OpenCV: Canny边缘检测算法原理及其VC实现详解
- Halcon实例教程之金属表面划痕及裂缝检测
- 使用QT和opencv3.3进行目标检测(YOLO)
- 图像角点检测之Trajkovic算子
- PCA检测人脸的简单示例_matlab实现
- 鲁大师怎么检测电脑是否有间谍软件?
- CNSCN安全性能检测
- 如何实现WinCE系统中USB设备自动检测
- poj2287 Tian Ji -- The Horse Racing(2016xynu暑期集训检测 -----C题)
- 忽略检测png文件
- 密码强度检测程序
- 开篇-HOG提取训练检测+样本制作
- NSIS检测.NET Framework并在线下载
- opencv 边缘检测 Contours 算法
- 一次完整的入侵检测
- 检测点6.1
- iOS开发-检测用户截屏, 并获取所截图片