DFS检测环路
1.marked数组初始化为0,初始节点随便选一个;
2.标记当前节点(marked数组对应位置变为1),检测其是否存在环路(同时记录parent节点),如果当前节点的邻接节点v中(除parent外)有已经被marked的节点,则有环路存在,return true;
3.访问未被marked的邻接节点v,重复2过程;
4.没有环路存在,return false。
WQU检测环路
1.初始化WQU,此时所有节点均未连接;
2.选择graph中的任意一条edge,判断当前edge连接的两个顶点在WQU中是否属于同一集合(root相同),如果是,则graph中存在环路,return true;否则在WQU中将二者连接;
3.按照步骤2遍历graph中的其他edge。
java代码
使用如下所示的无向图作为示例
CheckCircle.java
import java.util.Arrays;
public class CheckCircle {
private Graph graph;
private int[] marked;
private WQU circleWQU;
CheckCircle(Graph graph) {
this.graph = graph;
}
private void init() {
/* 初始化marked数组
*/
this.marked = new int[graph.V()];
Arrays.fill(marked, 0);
this.circleWQU = new WQU();
}
public boolean DFSCheck() {
/* 使用DFS检测graph中是否存在环路
*/
init();
return DFScheckHelper(0, 0);
}
private boolean DFScheckHelper(int curNode, int parent) {
marked[curNode] = 1;
if (graph.adj(curNode) != null) {
for (int adj : graph.adj(curNode)) {
if (adj != parent && marked[adj] != 0) {
return true;
}
if (marked[adj] == 0 && DFScheckHelper(adj, curNode)) {
return true;
}
}
}
return false;
}
public boolean WQUCheck() {
/* 使用WQU检测graph中是否存在环路
*/
init();
for (Graph.Pair edge : graph.getEdges()) {
int v = edge.getV();
int w = edge.getW();
if (circleWQU.find(v) == circleWQU.find(w)) {
return true;
} else {
circleWQU.connect(v, w);
}
}
return false;
}
public static void main(String[] args) {
Graph test = new Graph(7);
test.addEdge(0, 1);
test.addEdge(0, 2);
test.addEdge(1, 3);
test.addEdge(3, 6);
test.addEdge(4, 6);
test.addEdge(4, 5);
test.addEdge(5, 6);
CheckCircle t = new CheckCircle(test);
System.out.println(t.DFSCheck());
System.out.println(t.WQUCheck());
}
}
Graph.java
import java.nio.channels.Pipe;
import java.util.*;
public class Graph {
/* 无向、无权图
*/
private List<Integer>[] ver;
private Set<Pair> edges;
Graph(int v) {
/* Create empty graph with v vertices
*/
ver = new List[v];
edges = new HashSet<>();
}
public class Pair {
private int v;
private int w;
Pair(int v, int w) {
this.v = v;
this.w = w;
}
public int getV() {
return v;
}
public int getW() {
return w;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Pair)) return false;
Pair pair = (Pair) o;
return (v == pair.v && w == pair.w) ||
(v == pair.w && w == pair.v);
}
@Override
public int hashCode() {
return Objects.hash(v, w);
}
}
public Set<Pair> getEdges() {
for (int i = 0; i < this.V(); i++) {
for (int adj : this.adj(i)) {
if (i < adj) {
addToEdge(i, adj);
} else {
addToEdge(adj, i);
}
}
}
return edges;
}
private void addToEdge(int a, int b) {
Pair t = new Pair(a, b);
edges.add(t);
}
public void addEdge(int v, int w) {
/* add an edge v-w
*/
if (ver[v] == null) {
ver[v] = new ArrayList<>();
}
if (ver[w] == null) {
ver[w] = new ArrayList<>();
}
ver[v].add(w);
ver[w].add(v);
}
Iterable<Integer> adj(int v) {
/* vertices adjacent to v
*/
return ver[v];
}
public int V() {
/* number of vertices
*/
return ver.length;
}
public int E() {
/* number of edges
*/
int res = 0;
for (int i = 0; i < ver.length; i++) {
res += ver[i].size();
}
return res / 2;
}
}
WQU的实现参考加权快速联合(Weighted Quick Union)算法原理及实现(Java)