如何在 Java 中实现无向环和有向环的检测
2022-04-06 10:34
1111 查看
无向环
一个含有环的无向图如下所示,其中有两个环,分别是 0-2-1-0 和 2-3-4-2:
要检测无向图中的环,可以使用深度优先搜索。假设从顶点 0 出发,再走到相邻的顶点 2,接着走到顶点 2 相邻的顶点 1,由于顶点 0 和顶点 1 相邻,并且顶点 0 被标记过了,说明我们饶了一圈,所以无向图中存在环。虽然顶点 2 和顶点 1 相邻,但是并不能说明存在环,因为我们就是从顶点 2 直接走到顶点 1 的,这二者只有边的关系。算法如下所示:
package com.zhiyiyo.graph; import com.zhiyiyo.collection.stack.LinkStack; import com.zhiyiyo.collection.stack.Stack; /** * 无向图中的环 */ public class Cycle { private boolean[] marked; private Graph graph; private boolean hasCycle; public Cycle(Graph graph) { this.graph = graph; marked = new boolean[graph.V()]; for (int v = 0; v < graph.V(); ++v) { if (!marked[v]) { dfs(v); } } } private void dfs(int s) { if (hasCycle()) return; Stack<Integer> vertexes = new LinkStack<>(); vertexes.push(s); marked[s] = true; int lastVertex = s; while (!vertexes.isEmpty()) { int v = vertexes.pop(); for (int w : graph.adj(v)) { if (!marked[w]) { marked[w] = true; vertexes.push(w); } else if (w != lastVertex) { hasCycle = true; return; } } lastVertex = v; } } /** * 图中是否有环 */ public boolean hasCycle() { return hasCycle; } }
有向环
有向图
有向图的实现方式和上一篇博客 《如何在 Java 中实现无向图》 中无向图的实现方式几乎一样,只是在添加边 v-w 时只在顶点 v 的链表上添加顶点 w,而不对顶点 w 的链表进行操作。如果把
LinkGraph中成员变量的访问权限改成
protected,只需继承并重写
addEdge方法即可:
package com.zhiyiyo.graph; public class LinkDigraph extends LinkGraph implements Digraph { public LinkDigraph(int V) { super(V); } @Override public void addEdge(int v, int w) { adj[v].push(w); E++; } @Override public Digraph reverse() { Digraph digraph = new LinkDigraph(V()); for (int v = 0; v < V(); ++v) { for (int w : adj(v)) { digraph.addEdge(w, v); } } return digraph; } }
检测算法
一个含有有向环的有向图如下所示,其中 5-4-3-5 构成了一个环:
这里使用递归实现的深度优先搜索来检测有向环。假设从顶点 0 开始走,一路经过 5、4、3 这三个顶点,最终又碰到了与顶点 3 相邻的顶点 5,这时候如果知道顶点 5 已经被访问过了,并且递归函数还被压在栈中,就说明深度优先搜索从顶点 5 开始走,又回到了顶点 5,也就是找到了有向环。算法如下所示:
package com.zhiyiyo.graph; import com.zhiyiyo.collection.stack.LinkStack; import com.zhiyiyo.collection.stack.Stack; /** * 有向图中的环 */ public class DirectedCycle { private boolean[] marked; private boolean[] onStack; private int[] edgeTo; private Graph graph; private Stack<Integer> cycle; public DirectedCycle(Digraph graph) { this.graph = graph; marked = new boolean[graph.V()]; onStack = new boolean[graph.V()]; edgeTo = new int[graph.V()]; for (int v = 0; v < graph.V(); ++v) { if (!marked[v]) { dfs(v); } } } private void dfs(int v) { marked[v] = true; onStack[v] = true; for (int w : graph.adj(v)) { if (hasCycle()) return; if (!marked[w]) { marked[w] = true; edgeTo[w] = v; dfs(w); } else if (onStack[w]) { cycle = new LinkStack<>(); cycle.push(w); for (int i = v; i != w; i = edgeTo[i]) { cycle.push(i); } cycle.push(w); } } onStack[v] = false; } /** * 图中是否有环 */ public boolean hasCycle() { return cycle != null; } /** * 图中的一个环 */ public Iterable<Integer> cycle() { return cycle; } }
相关文章推荐
- java实现单项链表以及如何检测回环
- 关于“如何检测节点网络中是否存在闭环之java实现”的程序bug修复
- 如何用Java实现Web服务器(转-->)
- Java初学者如何迈出AOP第一步--使用Java 动态代理实现AOP
- CRC32算法学习笔记以及如何用java实现(一)
- 如何用java实现在网页中保存html编辑器 编辑好的 html 文件?!(如blog里发文章的时候把要发表的内容以html文件的形式保存到服务器上?)
- Tom White 是 Kizoom 的首席 Java 开发人员 实现的 如何实现每天定时对数据库的操作
- Java Web中的入侵检测及简单实现
- 如何使用java程序实现windows锁屏
- java中如何实现表格的多表头显示
- 想对jpeg格式图像进行压缩(不是缩略图),压缩后还是jpeg格式,在java中如何实现
- 如何真正实现Java程序的跨平台运行
- 如何用JAVA实现数字转换为大写?
- 如何在Java中实现远程方法调用
- 如何读字节从输入流取bit作位运算(JAVA实现)
- 在JAVA中如何实现浮点数的计算
- 如何实现Java无缝socket编程
- 如何让程序检测你的按键,实现WEB热键功能呢?
- Java Web中的入侵检测及简单实现
- 在Java applet中如何实现一个模式对话框?