Skip to content

Commit ee52cfc

Browse files
authored
Merge branch 'master' into kosaraju_improve
2 parents 8597fcc + 13be250 commit ee52cfc

File tree

7 files changed

+285
-118
lines changed

7 files changed

+285
-118
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,7 @@
810810
* [FordFulkersonTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/FordFulkersonTest.java)
811811
* [HamiltonianCycleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/HamiltonianCycleTest.java)
812812
* [JohnsonsAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithmTest.java)
813+
* [KahnsAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithmTest.java)
813814
* [KosarajuTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/KosarajuTest.java)
814815
* [TarjansAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/TarjansAlgorithmTest.java)
815816
* [WelshPowellTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/WelshPowellTest.java)
Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
package com.thealgorithms.datastructures.graphs;
22

3+
import java.util.Arrays;
4+
35
/**
4-
* Java program for Hamiltonian Cycle
5-
* <a href="https://en.wikipedia.org/wiki/Hamiltonian_path">wikipedia</a>
6+
* Java program to find a Hamiltonian Cycle in a graph.
7+
* A Hamiltonian Cycle is a cycle that visits every vertex exactly once
8+
* and returns to the starting vertex.
9+
*
10+
* <p>For more details, see the
11+
* <a href="https://en.wikipedia.org/wiki/Hamiltonian_path">Wikipedia article</a>.
612
*
713
* @author <a href="https://github.com/itsAkshayDubey">Akshay Dubey</a>
814
*/
@@ -14,30 +20,30 @@ public class HamiltonianCycle {
1420
private int[][] graph;
1521

1622
/**
17-
* Find hamiltonian cycle for given graph G(V,E)
23+
* Finds a Hamiltonian Cycle for the given graph.
1824
*
19-
* @param graph Adjacency matrix of a graph G(V, E)
20-
* for which hamiltonian path is to be found
21-
* @return Array containing hamiltonian cycle
22-
* else returns 1D array with value -1.
25+
* @param graph Adjacency matrix representing the graph G(V, E), where V is
26+
* the set of vertices and E is the set of edges.
27+
* @return An array representing the Hamiltonian cycle if found, otherwise an
28+
* array filled with -1 indicating no Hamiltonian cycle exists.
2329
*/
2430
public int[] findHamiltonianCycle(int[][] graph) {
31+
// Single vertex graph
32+
if (graph.length == 1) {
33+
return new int[] {0, 0};
34+
}
35+
2536
this.vertex = graph.length;
2637
this.cycle = new int[this.vertex + 1];
2738

28-
// Initialize path array with -1 value
29-
for (int i = 0; i < this.cycle.length; i++) {
30-
this.cycle[i] = -1;
31-
}
39+
// Initialize the cycle array with -1 to represent unvisited vertices
40+
Arrays.fill(this.cycle, -1);
3241

3342
this.graph = graph;
34-
3543
this.cycle[0] = 0;
3644
this.pathCount = 1;
3745
if (!isPathFound(0)) {
38-
for (int i = 0; i < this.cycle.length; i++) {
39-
this.cycle[i] = -1;
40-
}
46+
Arrays.fill(this.cycle, -1);
4147
} else {
4248
this.cycle[this.cycle.length - 1] = this.cycle[0];
4349
}
@@ -46,62 +52,55 @@ public int[] findHamiltonianCycle(int[][] graph) {
4652
}
4753

4854
/**
49-
* function to find paths recursively
50-
* Find paths recursively from given vertex
55+
* Recursively searches for a Hamiltonian cycle from the given vertex.
5156
*
52-
* @param vertex Vertex from which path is to be found
53-
* @returns true if path is found false otherwise
57+
* @param vertex The current vertex from which to explore paths.
58+
* @return {@code true} if a Hamiltonian cycle is found, otherwise {@code false}.
5459
*/
5560
public boolean isPathFound(int vertex) {
5661
boolean isLastVertexConnectedToStart = this.graph[vertex][0] == 1 && this.pathCount == this.vertex;
5762
if (isLastVertexConnectedToStart) {
5863
return true;
5964
}
6065

61-
/* all vertices selected but last vertex not linked to 0 **/
66+
// If all vertices are visited but the last vertex is not connected to the start
6267
if (this.pathCount == this.vertex) {
6368
return false;
6469
}
6570

6671
for (int v = 0; v < this.vertex; v++) {
67-
/* if connected **/
68-
if (this.graph[vertex][v] == 1) {
69-
/* add to path **/
70-
this.cycle[this.pathCount++] = v;
71-
72-
/* remove connection **/
72+
if (this.graph[vertex][v] == 1) { // Check if there is an edge
73+
this.cycle[this.pathCount++] = v; // Add the vertex to the cycle
7374
this.graph[vertex][v] = 0;
7475
this.graph[v][vertex] = 0;
7576

76-
/* if vertex not already selected solve recursively **/
77+
// Recursively attempt to complete the cycle
7778
if (!isPresent(v)) {
7879
return isPathFound(v);
7980
}
8081

81-
/* restore connection **/
82+
// Restore the edge if the path does not work
8283
this.graph[vertex][v] = 1;
8384
this.graph[v][vertex] = 1;
8485

85-
/* remove path **/
8686
this.cycle[--this.pathCount] = -1;
8787
}
8888
}
8989
return false;
9090
}
9191

9292
/**
93-
* function to check if path is already selected
94-
* Check if path is already selected
93+
* Checks if a vertex is already part of the current Hamiltonian path.
9594
*
96-
* @param vertex Starting vertex
95+
* @param vertex The vertex to check.
96+
* @return {@code true} if the vertex is already in the path, otherwise {@code false}.
9797
*/
9898
public boolean isPresent(int vertex) {
9999
for (int i = 0; i < pathCount - 1; i++) {
100100
if (cycle[i] == vertex) {
101101
return true;
102102
}
103103
}
104-
105104
return false;
106105
}
107106
}

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

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,18 @@
2121
*/
2222
public final class JohnsonsAlgorithm {
2323

24-
// Constant representing infinity
2524
private static final double INF = Double.POSITIVE_INFINITY;
2625

27-
/**
28-
* A private constructor to hide the implicit public one.
29-
*/
3026
private JohnsonsAlgorithm() {
3127
}
3228

3329
/**
3430
* Executes Johnson's algorithm on the given graph.
31+
* Steps:
32+
* 1. Add a new vertex to the graph and run Bellman-Ford to compute modified weights
33+
* 2. t the graph using the modified weights
34+
* 3. Run Dijkstra's algorithm for each vertex to compute the shortest paths
35+
* The final result is a 2D array of shortest distances between all pairs of vertices.
3536
*
3637
* @param graph The input graph represented as an adjacency matrix.
3738
* @return A 2D array representing the shortest distances between all pairs of vertices.
@@ -40,13 +41,10 @@ public static double[][] johnsonAlgorithm(double[][] graph) {
4041
int numVertices = graph.length;
4142
double[][] edges = convertToEdgeList(graph);
4243

43-
// Step 1: Add a new vertex and run Bellman-Ford
4444
double[] modifiedWeights = bellmanFord(edges, numVertices);
4545

46-
// Step 2: Reweight the graph
4746
double[][] reweightedGraph = reweightGraph(graph, modifiedWeights);
4847

49-
// Step 3: Run Dijkstra's algorithm for each vertex
5048
double[][] shortestDistances = new double[numVertices][numVertices];
5149
for (int source = 0; source < numVertices; source++) {
5250
shortestDistances[source] = dijkstra(reweightedGraph, source, modifiedWeights);
@@ -74,7 +72,6 @@ public static double[][] convertToEdgeList(double[][] graph) {
7472
}
7573
}
7674

77-
// Convert the List to a 2D array
7875
return edgeList.toArray(new double[0][]);
7976
}
8077

@@ -89,7 +86,7 @@ public static double[][] convertToEdgeList(double[][] graph) {
8986
private static double[] bellmanFord(double[][] edges, int numVertices) {
9087
double[] dist = new double[numVertices + 1];
9188
Arrays.fill(dist, INF);
92-
dist[numVertices] = 0; // Distance to the new source vertex is 0
89+
dist[numVertices] = 0;
9390

9491
// Add edges from the new vertex to all original vertices
9592
double[][] allEdges = Arrays.copyOf(edges, edges.length + numVertices);

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

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,96 +9,120 @@
99
import java.util.Set;
1010

1111
/**
12-
* A class that represents the adjaceny list of a graph
12+
* A class representing the adjacency list of a directed graph. The adjacency list
13+
* maintains a mapping of vertices to their adjacent vertices.
14+
*
15+
* @param <E> the type of vertices, extending Comparable to ensure that vertices
16+
* can be compared
1317
*/
1418
class AdjacencyList<E extends Comparable<E>> {
1519

1620
Map<E, ArrayList<E>> adj;
1721

22+
/**
23+
* Constructor to initialize the adjacency list.
24+
*/
1825
AdjacencyList() {
19-
adj = new LinkedHashMap<E, ArrayList<E>>();
26+
adj = new LinkedHashMap<>();
2027
}
2128

2229
/**
23-
* This function adds an Edge to the adjaceny list
30+
* Adds a directed edge from one vertex to another in the adjacency list.
31+
* If the vertex does not exist, it will be added to the list.
2432
*
25-
* @param from , the vertex the edge is from
26-
* @param to, the vertex the edge is going to
33+
* @param from the starting vertex of the directed edge
34+
* @param to the destination vertex of the directed edge
2735
*/
2836
void addEdge(E from, E to) {
29-
try {
30-
adj.get(from).add(to);
31-
} catch (Exception E) {
32-
adj.put(from, new ArrayList<E>());
33-
adj.get(from).add(to);
37+
if (!adj.containsKey(from)) {
38+
adj.put(from, new ArrayList<>());
3439
}
40+
adj.get(from).add(to);
3541
if (!adj.containsKey(to)) {
36-
adj.put(to, new ArrayList<E>());
42+
adj.put(to, new ArrayList<>());
3743
}
3844
}
3945

4046
/**
41-
* @param v, A vertex in a graph
42-
* @return returns an ArrayList of all the adjacents of vertex v
47+
* Retrieves the list of adjacent vertices for a given vertex.
48+
*
49+
* @param v the vertex whose adjacent vertices are to be fetched
50+
* @return an ArrayList of adjacent vertices for vertex v
4351
*/
4452
ArrayList<E> getAdjacents(E v) {
4553
return adj.get(v);
4654
}
4755

4856
/**
49-
* @return returns a set of all vertices in the graph
57+
* Retrieves the set of all vertices present in the graph.
58+
*
59+
* @return a set containing all vertices in the graph
5060
*/
5161
Set<E> getVertices() {
5262
return adj.keySet();
5363
}
5464
}
5565

66+
/**
67+
* A class that performs topological sorting on a directed graph using Kahn's algorithm.
68+
*
69+
* @param <E> the type of vertices, extending Comparable to ensure that vertices
70+
* can be compared
71+
*/
5672
class TopologicalSort<E extends Comparable<E>> {
5773

5874
AdjacencyList<E> graph;
5975
Map<E, Integer> inDegree;
6076

77+
/**
78+
* Constructor to initialize the topological sorting class with a given graph.
79+
*
80+
* @param graph the directed graph represented as an adjacency list
81+
*/
6182
TopologicalSort(AdjacencyList<E> graph) {
6283
this.graph = graph;
6384
}
6485

6586
/**
66-
* Calculates the in degree of all vertices
87+
* Calculates the in-degree of all vertices in the graph. The in-degree is
88+
* the number of edges directed into a vertex.
6789
*/
6890
void calculateInDegree() {
6991
inDegree = new HashMap<>();
7092
for (E vertex : graph.getVertices()) {
71-
if (!inDegree.containsKey(vertex)) {
72-
inDegree.put(vertex, 0);
73-
}
93+
inDegree.putIfAbsent(vertex, 0);
7494
for (E adjacent : graph.getAdjacents(vertex)) {
75-
try {
76-
inDegree.put(adjacent, inDegree.get(adjacent) + 1);
77-
} catch (Exception e) {
78-
inDegree.put(adjacent, 1);
79-
}
95+
inDegree.put(adjacent, inDegree.getOrDefault(adjacent, 0) + 1);
8096
}
8197
}
8298
}
8399

84100
/**
85-
* Returns an ArrayList with vertices arranged in topological order
101+
* Returns an ArrayList containing the vertices of the graph arranged in
102+
* topological order. Topological sorting ensures that for any directed edge
103+
* (u, v), vertex u appears before vertex v in the ordering.
104+
*
105+
* @return an ArrayList of vertices in topological order
106+
* @throws IllegalStateException if the graph contains a cycle
86107
*/
87108
ArrayList<E> topSortOrder() {
88109
calculateInDegree();
89-
Queue<E> q = new LinkedList<E>();
110+
Queue<E> q = new LinkedList<>();
90111

91-
for (final var entry : inDegree.entrySet()) {
112+
for (var entry : inDegree.entrySet()) {
92113
if (entry.getValue() == 0) {
93114
q.add(entry.getKey());
94115
}
95116
}
96117

97118
ArrayList<E> answer = new ArrayList<>();
119+
int processedVertices = 0;
98120

99121
while (!q.isEmpty()) {
100122
E current = q.poll();
101123
answer.add(current);
124+
processedVertices++;
125+
102126
for (E adjacent : graph.getAdjacents(current)) {
103127
inDegree.put(adjacent, inDegree.get(adjacent) - 1);
104128
if (inDegree.get(adjacent) == 0) {
@@ -107,12 +131,16 @@ ArrayList<E> topSortOrder() {
107131
}
108132
}
109133

134+
if (processedVertices != graph.getVertices().size()) {
135+
throw new IllegalStateException("Graph contains a cycle, topological sort not possible");
136+
}
137+
110138
return answer;
111139
}
112140
}
113141

114142
/**
115-
* A driver class that sorts a given graph in topological order.
143+
* A driver class that sorts a given graph in topological order using Kahn's algorithm.
116144
*/
117145
public final class KahnsAlgorithm {
118146
private KahnsAlgorithm() {
@@ -130,7 +158,7 @@ public static void main(String[] args) {
130158

131159
TopologicalSort<String> topSort = new TopologicalSort<>(graph);
132160

133-
// Printing the order
161+
// Printing the topological order
134162
for (String s : topSort.topSortOrder()) {
135163
System.out.print(s + " ");
136164
}

0 commit comments

Comments
 (0)