Skip to content

Commit 6faef1a

Browse files
author
Divyansh Saxena
committed
feat: add graph cycle detection algorithm and its unit tests.
1 parent dc3d64f commit 6faef1a

3 files changed

Lines changed: 112 additions & 38 deletions

File tree

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
<arg>-Xlint:all</arg>
7777
<arg>-Xlint:-auxiliaryclass</arg>
7878
<arg>-Werror</arg>
79+
7980
</compilerArgs>
8081
</configuration>
8182
</plugin>

src/main/java/com/thealgorithms/datastructures/graphs/Cycles.java

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,42 @@
11
package com.thealgorithms.datastructures.graphs;
22

33
import java.util.ArrayList;
4-
import java.util.Scanner;
4+
import java.util.List;
55

66
class Cycle {
77

88
private final int nodes;
9-
private int[][] adjacencyMatrix;
10-
private boolean[] visited;
11-
ArrayList<ArrayList<Integer>> cycles = new ArrayList<ArrayList<Integer>>();
12-
13-
Cycle() {
14-
Scanner in = new Scanner(System.in);
15-
System.out.print("Enter the no. of nodes: ");
16-
nodes = in.nextInt();
17-
System.out.print("Enter the no. of Edges: ");
18-
final int edges = in.nextInt();
19-
20-
adjacencyMatrix = new int[nodes][nodes];
21-
visited = new boolean[nodes];
9+
private final int[][] adjacencyMatrix;
10+
private final boolean[] visited;
11+
private final List<List<Integer>> cycles = new ArrayList<>();
2212

13+
Cycle(int nodes, int[][] adjacencyMatrix) {
14+
this.nodes = nodes;
15+
this.adjacencyMatrix = new int[nodes][nodes];
16+
// Deep copy matrix to avoid side-effects
2317
for (int i = 0; i < nodes; i++) {
24-
visited[i] = false;
25-
}
26-
27-
System.out.println("Enter the details of each edges <Start Node> <End Node>");
28-
29-
for (int i = 0; i < edges; i++) {
30-
int start;
31-
int end;
32-
start = in.nextInt();
33-
end = in.nextInt();
34-
adjacencyMatrix[start][end] = 1;
18+
System.arraycopy(adjacencyMatrix[i], 0, this.adjacencyMatrix[i], 0, nodes);
3519
}
36-
in.close();
20+
this.visited = new boolean[nodes];
3721
}
3822

3923
public void start() {
4024
for (int i = 0; i < nodes; i++) {
41-
ArrayList<Integer> temp = new ArrayList<>();
42-
dfs(i, i, temp);
25+
dfs(i, i, new ArrayList<>());
4326
for (int j = 0; j < nodes; j++) {
44-
adjacencyMatrix[i][j] = 0;
45-
adjacencyMatrix[j][i] = 0;
27+
this.adjacencyMatrix[i][j] = 0;
28+
this.adjacencyMatrix[j][i] = 0;
4629
}
4730
}
4831
}
4932

50-
private void dfs(Integer start, Integer curr, ArrayList<Integer> temp) {
33+
private void dfs(int start, int curr, List<Integer> temp) {
5134
temp.add(curr);
5235
visited[curr] = true;
5336
for (int i = 0; i < nodes; i++) {
5437
if (adjacencyMatrix[curr][i] == 1) {
5538
if (i == start) {
56-
cycles.add(new ArrayList<Integer>(temp));
39+
cycles.add(new ArrayList<>(temp));
5740
} else {
5841
if (!visited[i]) {
5942
dfs(start, i, temp);
@@ -62,18 +45,24 @@ private void dfs(Integer start, Integer curr, ArrayList<Integer> temp) {
6245
}
6346
}
6447

65-
if (temp.size() > 0) {
48+
if (!temp.isEmpty()) {
6649
temp.remove(temp.size() - 1);
6750
}
6851
visited[curr] = false;
6952
}
7053

54+
public List<List<Integer>> getCycles() {
55+
return cycles;
56+
}
57+
7158
public void printAll() {
72-
for (int i = 0; i < cycles.size(); i++) {
73-
for (int j = 0; j < cycles.get(i).size(); j++) {
74-
System.out.print(cycles.get(i).get(j) + " -> ");
59+
for (List<Integer> cycle : cycles) {
60+
for (Integer node : cycle) {
61+
System.out.print(node + " -> ");
62+
}
63+
if (!cycle.isEmpty()) {
64+
System.out.println(cycle.get(0));
7565
}
76-
System.out.println(cycles.get(i).get(0));
7766
System.out.println();
7867
}
7968
}
@@ -84,7 +73,15 @@ private Cycles() {
8473
}
8574

8675
public static void main(String[] args) {
87-
Cycle c = new Cycle();
76+
// Example usage with a triangle graph: 0 -> 1 -> 2 -> 0
77+
int nodes = 3;
78+
int[][] matrix = {
79+
{ 0, 1, 1 },
80+
{ 1, 0, 1 },
81+
{ 1, 1, 0 }
82+
};
83+
84+
Cycle c = new Cycle(nodes, matrix);
8885
c.start();
8986
c.printAll();
9087
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.thealgorithms.datastructures.graphs;
2+
3+
import org.junit.jupiter.api.Test;
4+
import java.util.List;
5+
import static org.junit.jupiter.api.Assertions.assertEquals;
6+
import static org.junit.jupiter.api.Assertions.assertFalse;
7+
import static org.junit.jupiter.api.Assertions.assertTrue;
8+
9+
class CyclesTest {
10+
11+
@Test
12+
void testTriangleCycle() {
13+
// Triangle graph: 0-1, 1-2, 2-0
14+
int nodes = 3;
15+
int[][] matrix = {
16+
{ 0, 1, 1 },
17+
{ 1, 0, 1 },
18+
{ 1, 1, 0 }
19+
};
20+
21+
Cycle c = new Cycle(nodes, matrix);
22+
c.start();
23+
List<List<Integer>> cycles = c.getCycles();
24+
25+
// Should find at least one cycle: [0, 1, 2]
26+
// Note: The algorithm modifies the matrix as it goes, so it finds elementary
27+
// cycles.
28+
// For a triangle, it finds 0-1-2.
29+
30+
assertFalse(cycles.isEmpty(), "Should detect at least one cycle");
31+
// Verify the cycle content
32+
boolean foundTriangle = false;
33+
for (List<Integer> cycle : cycles) {
34+
if (cycle.size() == 3 && cycle.contains(0) && cycle.contains(1) && cycle.contains(2)) {
35+
foundTriangle = true;
36+
break;
37+
}
38+
}
39+
assertTrue(foundTriangle, "Should detect the 0-1-2 triangle");
40+
}
41+
42+
@Test
43+
void testNoCycle() {
44+
// Line graph: 0 -> 1 -> 2
45+
int nodes = 3;
46+
int[][] matrix = {
47+
{ 0, 1, 0 },
48+
{ 0, 0, 1 },
49+
{ 0, 0, 0 }
50+
};
51+
52+
Cycle c = new Cycle(nodes, matrix);
53+
c.start();
54+
List<List<Integer>> cycles = c.getCycles();
55+
56+
assertTrue(cycles.isEmpty(), "Should not detect any cycles in a line graph");
57+
}
58+
59+
@Test
60+
void testSelfLoop() {
61+
// Node 0 has self loop
62+
int nodes = 1;
63+
int[][] matrix = {
64+
{ 1 }
65+
};
66+
67+
Cycle c = new Cycle(nodes, matrix);
68+
c.start();
69+
List<List<Integer>> cycles = c.getCycles();
70+
71+
assertFalse(cycles.isEmpty(), "Should detect self loop");
72+
assertEquals(1, cycles.size());
73+
assertEquals(1, cycles.get(0).size());
74+
assertEquals(0, cycles.get(0).get(0));
75+
}
76+
}

0 commit comments

Comments
 (0)