I am using Algorithms 4th edition to polish up my graph theory a bit. The books comes with a lot of code for graph processing.
Currently, I am stuck with the following problems: How to find all cycles in an undirected graph? I was looking to modify the existing code for cycle detection to do that.
Here is the important part:
private void dfs(Graph G, int u, int v) {
marked[v] = true;
for (int w : G.adj(v)) {
// short circuit if cycle already found
if (cycle != null) return;
if (!marked[w]) {
edgeTo[w] = v;
dfs(G, v, w);
}
// check for cycle (but disregard reverse of edge leading to v)
else if (w != u) {
cycle = new Stack<Integer>();
for (int x = v; x != w; x = edgeTo[x]) {
cycle.push(x);
}
cycle.push(w);
cycle.push(v);
}
}
}
Now, if I were to find ALL cycles, I should remove the line that returns when a cycle is found and each time a cycle is created I would store it. The part I cannot figure out is: when does the algorithm stop? How can I be sure I have found all cycles?
Can the above code even be modified in a way to allow me to find all cycles?
Cycle detection is much easier than finding all cycles. Cycle detection can be done in linear time using a DFS like you've linked, but the number of cycles in a graph can be exponential, ruling out an polytime algorithm altogether. If you don't see how this could be possible, consider this graph:
1 -- 2
| / |
| / |
3 -- 4
There are three distinct cycles, but a DFS would find only two back-edges.
As such, modifying your algorithm to find all cycles will take a fair bit more work than simply changing a line or two. Instead, you have to find a set of base cycles, then combine them to form the set of all cycles. You can find an implementation of an algorithm that'll does this in this question .
/**
* In this program we create a list of edges which is an ordered pair of two
* integers representing two vertices.
*
* We iterate through each edge and apply Union Find algorithm to detect
* cycle.
*
* This is a tested code and gives correct result for all inputs.
*/
package com.divyanshu.ds.disjointSet;
import java.util.HashMap;
/**
* @author Divyanshu
* DisjointSet is a data structure with three operations :
* makeSet, union and findSet
*
* Algorithms Used : Union by rank and path compression for detecting cycles
* in an undirected graph.
*/
public class DisjontSet {
HashMap<Long, Node> map = new HashMap<>();
class Node {
long data;
Node parent;
int rank;
}
public void makeSet(long data) {
Node node = new Node();
node.data = data;
node.parent = node;
node.rank = 0;
map.put(data, node);
}
public void union(long firstSet,
long secondSet) {
Node firstNode = map.get(firstSet);
Node secondNode = map.get(secondSet);
Node firstParent = findSet(firstNode);
Node secondParent = findSet(secondNode);
if (firstParent.data == secondParent.data) {
return;
}
if (firstParent.rank >= secondParent.rank) {
firstParent.rank = (firstParent.rank == secondParent.rank) ? firstParent.rank + 1 : firstParent.rank;
secondParent.parent = firstParent;
} else {
firstParent.parent = secondParent;
}
}
public long findSet(long data) {
return findSet(map.get(data)).data;
}
private Node findSet(Node node) {
if (node.parent == node) {
return node;
}
node.parent = findSet(node.parent);
return node.parent;
}
}
=============================================================================
package com.divyanshu.ds.client;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import com.divyanshu.ds.disjointSet.DisjontSet;
import com.divyanshu.ds.disjointSet.Edge;
public class DisjointSetClient {
public static void main(String[] args) {
int edgeCount = 4;
int vertexCount = 12;
List<Edge> graph = generateGraph(edgeCount, vertexCount);
System.out.println("Generated Graph : ");
System.out.println(graph);
DisjontSet disjontSet = getDisjointSet(graph);
Boolean isGraphCyclic = isGraphCyclic(graph, disjontSet);
System.out.println("Graph contains cycle : " + isGraphCyclic);
}
private static Boolean isGraphCyclic(List<Edge> graph,
DisjontSet disjontSet) {
Boolean isGraphCyclic = false;
for (Edge edge : graph) {
if (edge.getFirstVertex() != edge.getSecondVertex()) {
Long first = disjontSet.findSet(edge.getFirstVertex());
Long second = disjontSet.findSet(edge.getSecondVertex());
if (first.equals(second)) {
isGraphCyclic = true;
break;
} else {
disjontSet.union(first, second);
}
}
}
return isGraphCyclic;
}
private static DisjontSet getDisjointSet(List<Edge> graph) {
DisjontSet disjontSet = new DisjontSet();
for (Edge edge : graph) {
disjontSet.makeSet(edge.getFirstVertex());
disjontSet.makeSet(edge.getSecondVertex());
}
return disjontSet;
}
private static List<Edge> generateGraph(int edgeCount,
int vertexCount) {
List<Edge> graph = new ArrayList<>();
HashSet<Edge> edgeSet = new HashSet<>();
Random random = new Random();
for (int j = 0; j < vertexCount; j++) {
int first = random.nextInt(edgeCount);
int second = random.nextInt(edgeCount);
if (first != second) {
edgeSet.add(new Edge(first, second));
} else {
j--;
}
}
for (Edge edge : edgeSet) {
graph.add(edge);
}
return graph;
}
}
===================================================================
/**
*
*/
package com.divyanshu.ds.disjointSet;
/**
* @author Divyanshu
*
*/
public class Edge {
private long firstVertex;
private long secondVertex;
public Edge(long firstVertex,
long secondVertex) {
this.firstVertex = firstVertex;
this.secondVertex = secondVertex;
}
public long getFirstVertex() {
return firstVertex;
}
public void setFirstVertex(long firstVertex) {
this.firstVertex = firstVertex;
}
public long getSecondVertex() {
return secondVertex;
}
public void setSecondVertex(long secondVertex) {
this.secondVertex = secondVertex;
}
@Override
public String toString() {
return "(" + firstVertex + "," + secondVertex + ")";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (firstVertex ^ (firstVertex >>> 32));
result = prime * result + (int) (secondVertex ^ (secondVertex >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Edge other = (Edge) obj;
if (firstVertex != other.firstVertex)
return false;
if (secondVertex != other.secondVertex)
return false;
return true;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.