diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/WelshPowell.java b/src/main/java/com/thealgorithms/datastructures/graphs/WelshPowell.java
index 0981638d4..26ca97736 100644
--- a/src/main/java/com/thealgorithms/datastructures/graphs/WelshPowell.java
+++ b/src/main/java/com/thealgorithms/datastructures/graphs/WelshPowell.java
@@ -5,21 +5,41 @@ import java.util.Comparator;
import java.util.HashSet;
import java.util.stream.IntStream;
-/*
- * The Welsh-Powell algorithm is a graph coloring algorithm
- * used for coloring a graph with the minimum number of colors.
- * https://en.wikipedia.org/wiki/Graph_coloring
+/**
+ * The Welsh-Powell algorithm is a graph coloring algorithm that aims to color a graph
+ * using the minimum number of colors such that no two adjacent vertices share the same color.
+ *
+ *
+ * The algorithm works by:
+ *
+ * - Sorting the vertices in descending order based on their degrees (number of edges connected).
+ * - Iterating through each vertex and assigning it the smallest available color that has not been used by its adjacent vertices.
+ * - Coloring adjacent vertices with the same color is avoided.
+ *
+ *
+ *
+ *
+ * For more information, see Graph Coloring.
+ *
*/
-
public final class WelshPowell {
- private static final int BLANK_COLOR = -1; // Representing uncolored state
+ private static final int BLANK_COLOR = -1; // Constant representing an uncolored state
private WelshPowell() {
}
+ /**
+ * Represents a graph using an adjacency list.
+ */
static final class Graph {
- private HashSet[] adjacencyLists;
+ private final HashSet[] adjacencyLists;
+ /**
+ * Initializes a graph with a specified number of vertices.
+ *
+ * @param vertices the number of vertices in the graph
+ * @throws IllegalArgumentException if the number of vertices is negative
+ */
private Graph(int vertices) {
if (vertices < 0) {
throw new IllegalArgumentException("Number of vertices cannot be negative");
@@ -29,6 +49,13 @@ public final class WelshPowell {
Arrays.setAll(adjacencyLists, i -> new HashSet<>());
}
+ /**
+ * Adds an edge between two vertices in the graph.
+ *
+ * @param nodeA one end of the edge
+ * @param nodeB the other end of the edge
+ * @throws IllegalArgumentException if the vertices are out of bounds or if a self-loop is attempted
+ */
private void addEdge(int nodeA, int nodeB) {
validateVertex(nodeA);
validateVertex(nodeB);
@@ -39,21 +66,46 @@ public final class WelshPowell {
adjacencyLists[nodeB].add(nodeA);
}
+ /**
+ * Validates that the vertex index is within the bounds of the graph.
+ *
+ * @param vertex the index of the vertex to validate
+ * @throws IllegalArgumentException if the vertex is out of bounds
+ */
private void validateVertex(int vertex) {
if (vertex < 0 || vertex >= getNumVertices()) {
throw new IllegalArgumentException("Vertex " + vertex + " is out of bounds");
}
}
+ /**
+ * Returns the adjacency list for a specific vertex.
+ *
+ * @param vertex the index of the vertex
+ * @return the set of adjacent vertices
+ */
HashSet getAdjacencyList(int vertex) {
return adjacencyLists[vertex];
}
+ /**
+ * Returns the number of vertices in the graph.
+ *
+ * @return the number of vertices
+ */
int getNumVertices() {
return adjacencyLists.length;
}
}
+ /**
+ * Creates a graph with the specified number of vertices and edges.
+ *
+ * @param numberOfVertices the total number of vertices
+ * @param listOfEdges a 2D array representing edges where each inner array contains two vertex indices
+ * @return a Graph object representing the created graph
+ * @throws IllegalArgumentException if the edge array is invalid or vertices are out of bounds
+ */
public static Graph makeGraph(int numberOfVertices, int[][] listOfEdges) {
Graph graph = new Graph(numberOfVertices);
for (int[] edge : listOfEdges) {
@@ -65,6 +117,12 @@ public final class WelshPowell {
return graph;
}
+ /**
+ * Finds the coloring of the given graph using the Welsh-Powell algorithm.
+ *
+ * @param graph the input graph to color
+ * @return an array of integers where each index represents a vertex and the value represents the color assigned
+ */
public static int[] findColoring(Graph graph) {
int[] colors = initializeColors(graph.getNumVertices());
Integer[] sortedVertices = getSortedNodes(graph);
@@ -83,30 +141,70 @@ public final class WelshPowell {
return colors;
}
+ /**
+ * Helper method to check if a color is unassigned
+ *
+ * @param color the color to check
+ * @return {@code true} if the color is unassigned, {@code false} otherwise
+ */
private static boolean isBlank(int color) {
return color == BLANK_COLOR;
}
+ /**
+ * Checks if a vertex has adjacent colored vertices
+ *
+ * @param graph the input graph
+ * @param vertex the vertex to check
+ * @param colors the array of colors assigned to the vertices
+ * @return {@code true} if the vertex has adjacent colored vertices, {@code false} otherwise
+ */
private static boolean isAdjacentToColored(Graph graph, int vertex, int[] colors) {
return graph.getAdjacencyList(vertex).stream().anyMatch(otherVertex -> !isBlank(colors[otherVertex]));
}
+ /**
+ * Initializes the colors array with blank color
+ *
+ * @param numberOfVertices the number of vertices in the graph
+ * @return an array of integers representing the colors assigned to the vertices
+ */
private static int[] initializeColors(int numberOfVertices) {
int[] colors = new int[numberOfVertices];
Arrays.fill(colors, BLANK_COLOR);
return colors;
}
+ /**
+ * Sorts the vertices by their degree in descending order
+ *
+ * @param graph the input graph
+ * @return an array of integers representing the vertices sorted by degree
+ */
private static Integer[] getSortedNodes(final Graph graph) {
return IntStream.range(0, graph.getNumVertices()).boxed().sorted(Comparator.comparingInt(v -> - graph.getAdjacencyList(v).size())).toArray(Integer[] ::new);
}
+ /**
+ * Computes the colors already used by the adjacent vertices
+ *
+ * @param graph the input graph
+ * @param vertex the vertex to check
+ * @param colors the array of colors assigned to the vertices
+ * @return an array of booleans representing the colors used by the adjacent vertices
+ */
private static boolean[] computeUsedColors(final Graph graph, final int vertex, final int[] colors) {
boolean[] usedColors = new boolean[graph.getNumVertices()];
graph.getAdjacencyList(vertex).stream().map(neighbor -> colors[neighbor]).filter(color -> !isBlank(color)).forEach(color -> usedColors[color] = true);
return usedColors;
}
+ /**
+ * Finds the first unused color
+ *
+ * @param usedColors the array of colors used by the adjacent vertices
+ * @return the first unused color
+ */
private static int firstUnusedColor(boolean[] usedColors) {
return IntStream.range(0, usedColors.length).filter(color -> !usedColors[color]).findFirst().getAsInt();
}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/WelshPowellTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/WelshPowellTest.java
index b37657db5..f45c4e10b 100644
--- a/src/test/java/com/thealgorithms/datastructures/graphs/WelshPowellTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/WelshPowellTest.java
@@ -34,26 +34,25 @@ class WelshPowellTest {
assertEquals(3, countDistinctColors(colors));
}
- // The following test originates from the following website : https://www.geeksforgeeks.org/welsh-powell-graph-colouring-algorithm/
@Test
void testComplexGraph() {
int[][] edges = {
- {0, 7}, // A-H
- {0, 1}, // A-B
- {1, 3}, // B-D
- {2, 3}, // C-D
- {3, 8}, // D-I
- {3, 10}, // D-K
- {4, 10}, // E-K
- {4, 5}, // E-F
- {5, 6}, // F-G
- {6, 10}, // G-K
- {6, 7}, // G-H
- {7, 8}, // H-I
- {7, 9}, // H-J
- {7, 10}, // H-K
- {8, 9}, // I-J
- {9, 10}, // J-K
+ {0, 7},
+ {0, 1},
+ {1, 3},
+ {2, 3},
+ {3, 8},
+ {3, 10},
+ {4, 10},
+ {4, 5},
+ {5, 6},
+ {6, 10},
+ {6, 7},
+ {7, 8},
+ {7, 9},
+ {7, 10},
+ {8, 9},
+ {9, 10},
};
final var graph = WelshPowell.makeGraph(11, edges); // 11 vertices from A (0) to K (10)
@@ -86,24 +85,35 @@ class WelshPowellTest {
@Test
void testWithPreColoredVertex() {
- // Create a linear graph with 4 vertices and edges connecting them in sequence
final var graph = WelshPowell.makeGraph(4, new int[][] {{0, 1}, {1, 2}, {2, 3}});
-
- // Apply the Welsh-Powell coloring algorithm to the graph
int[] colors = WelshPowell.findColoring(graph);
-
- // Validate that the coloring is correct (no two adjacent vertices have the same color)
assertTrue(isColoringValid(graph, colors));
-
- // Check if the algorithm has used at least 2 colors (expected for a linear graph)
assertTrue(countDistinctColors(colors) >= 2);
-
- // Verify that all vertices have been assigned a color
for (int color : colors) {
assertTrue(color >= 0);
}
}
+ @Test
+ void testLargeGraph() {
+ int[][] edges = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 0}, {6, 7}, {7, 8}, {8, 6}, {9, 10}, {10, 11}, {11, 9}, {12, 13}, {13, 14}, {14, 15}};
+
+ final var graph = WelshPowell.makeGraph(16, edges); // 16 vertices
+ int[] colors = WelshPowell.findColoring(graph);
+ assertTrue(isColoringValid(graph, colors));
+ assertEquals(3, countDistinctColors(colors)); // Expecting a maximum of 3 colors
+ }
+
+ @Test
+ void testStarGraph() {
+ int[][] edges = {{0, 1}, {0, 2}, {0, 3}, {0, 4}};
+
+ final var graph = WelshPowell.makeGraph(5, edges); // 5 vertices in a star formation
+ int[] colors = WelshPowell.findColoring(graph);
+ assertTrue(isColoringValid(graph, colors));
+ assertEquals(2, countDistinctColors(colors)); // Star graph can be colored with 2 colors
+ }
+
private boolean isColoringValid(Graph graph, int[] colors) {
if (Arrays.stream(colors).anyMatch(n -> n < 0)) {
return false;