Skip to content

Commit 474e0de

Browse files
authored
Enhance docs, add more tests in WelshPowell (TheAlgorithms#5971)
1 parent a78b15d commit 474e0de

File tree

2 files changed

+142
-34
lines changed

2 files changed

+142
-34
lines changed

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

Lines changed: 106 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,41 @@
55
import java.util.HashSet;
66
import java.util.stream.IntStream;
77

8-
/*
9-
* The Welsh-Powell algorithm is a graph coloring algorithm
10-
* used for coloring a graph with the minimum number of colors.
11-
* https://en.wikipedia.org/wiki/Graph_coloring
8+
/**
9+
* The Welsh-Powell algorithm is a graph coloring algorithm that aims to color a graph
10+
* using the minimum number of colors such that no two adjacent vertices share the same color.
11+
*
12+
* <p>
13+
* The algorithm works by:
14+
* <ol>
15+
* <li>Sorting the vertices in descending order based on their degrees (number of edges connected).</li>
16+
* <li>Iterating through each vertex and assigning it the smallest available color that has not been used by its adjacent vertices.</li>
17+
* <li>Coloring adjacent vertices with the same color is avoided.</li>
18+
* </ol>
19+
* </p>
20+
*
21+
* <p>
22+
* For more information, see <a href="https://en.wikipedia.org/wiki/Graph_coloring">Graph Coloring</a>.
23+
* </p>
1224
*/
13-
1425
public final class WelshPowell {
15-
private static final int BLANK_COLOR = -1; // Representing uncolored state
26+
private static final int BLANK_COLOR = -1; // Constant representing an uncolored state
1627

1728
private WelshPowell() {
1829
}
1930

31+
/**
32+
* Represents a graph using an adjacency list.
33+
*/
2034
static final class Graph {
21-
private HashSet<Integer>[] adjacencyLists;
22-
35+
private final HashSet<Integer>[] adjacencyLists;
36+
37+
/**
38+
* Initializes a graph with a specified number of vertices.
39+
*
40+
* @param vertices the number of vertices in the graph
41+
* @throws IllegalArgumentException if the number of vertices is negative
42+
*/
2343
private Graph(int vertices) {
2444
if (vertices < 0) {
2545
throw new IllegalArgumentException("Number of vertices cannot be negative");
@@ -29,6 +49,13 @@ private Graph(int vertices) {
2949
Arrays.setAll(adjacencyLists, i -> new HashSet<>());
3050
}
3151

52+
/**
53+
* Adds an edge between two vertices in the graph.
54+
*
55+
* @param nodeA one end of the edge
56+
* @param nodeB the other end of the edge
57+
* @throws IllegalArgumentException if the vertices are out of bounds or if a self-loop is attempted
58+
*/
3259
private void addEdge(int nodeA, int nodeB) {
3360
validateVertex(nodeA);
3461
validateVertex(nodeB);
@@ -39,21 +66,46 @@ private void addEdge(int nodeA, int nodeB) {
3966
adjacencyLists[nodeB].add(nodeA);
4067
}
4168

69+
/**
70+
* Validates that the vertex index is within the bounds of the graph.
71+
*
72+
* @param vertex the index of the vertex to validate
73+
* @throws IllegalArgumentException if the vertex is out of bounds
74+
*/
4275
private void validateVertex(int vertex) {
4376
if (vertex < 0 || vertex >= getNumVertices()) {
4477
throw new IllegalArgumentException("Vertex " + vertex + " is out of bounds");
4578
}
4679
}
4780

81+
/**
82+
* Returns the adjacency list for a specific vertex.
83+
*
84+
* @param vertex the index of the vertex
85+
* @return the set of adjacent vertices
86+
*/
4887
HashSet<Integer> getAdjacencyList(int vertex) {
4988
return adjacencyLists[vertex];
5089
}
5190

91+
/**
92+
* Returns the number of vertices in the graph.
93+
*
94+
* @return the number of vertices
95+
*/
5296
int getNumVertices() {
5397
return adjacencyLists.length;
5498
}
5599
}
56100

101+
/**
102+
* Creates a graph with the specified number of vertices and edges.
103+
*
104+
* @param numberOfVertices the total number of vertices
105+
* @param listOfEdges a 2D array representing edges where each inner array contains two vertex indices
106+
* @return a Graph object representing the created graph
107+
* @throws IllegalArgumentException if the edge array is invalid or vertices are out of bounds
108+
*/
57109
public static Graph makeGraph(int numberOfVertices, int[][] listOfEdges) {
58110
Graph graph = new Graph(numberOfVertices);
59111
for (int[] edge : listOfEdges) {
@@ -65,6 +117,12 @@ public static Graph makeGraph(int numberOfVertices, int[][] listOfEdges) {
65117
return graph;
66118
}
67119

120+
/**
121+
* Finds the coloring of the given graph using the Welsh-Powell algorithm.
122+
*
123+
* @param graph the input graph to color
124+
* @return an array of integers where each index represents a vertex and the value represents the color assigned
125+
*/
68126
public static int[] findColoring(Graph graph) {
69127
int[] colors = initializeColors(graph.getNumVertices());
70128
Integer[] sortedVertices = getSortedNodes(graph);
@@ -83,30 +141,70 @@ public static int[] findColoring(Graph graph) {
83141
return colors;
84142
}
85143

144+
/**
145+
* Helper method to check if a color is unassigned
146+
*
147+
* @param color the color to check
148+
* @return {@code true} if the color is unassigned, {@code false} otherwise
149+
*/
86150
private static boolean isBlank(int color) {
87151
return color == BLANK_COLOR;
88152
}
89153

154+
/**
155+
* Checks if a vertex has adjacent colored vertices
156+
*
157+
* @param graph the input graph
158+
* @param vertex the vertex to check
159+
* @param colors the array of colors assigned to the vertices
160+
* @return {@code true} if the vertex has adjacent colored vertices, {@code false} otherwise
161+
*/
90162
private static boolean isAdjacentToColored(Graph graph, int vertex, int[] colors) {
91163
return graph.getAdjacencyList(vertex).stream().anyMatch(otherVertex -> !isBlank(colors[otherVertex]));
92164
}
93165

166+
/**
167+
* Initializes the colors array with blank color
168+
*
169+
* @param numberOfVertices the number of vertices in the graph
170+
* @return an array of integers representing the colors assigned to the vertices
171+
*/
94172
private static int[] initializeColors(int numberOfVertices) {
95173
int[] colors = new int[numberOfVertices];
96174
Arrays.fill(colors, BLANK_COLOR);
97175
return colors;
98176
}
99177

178+
/**
179+
* Sorts the vertices by their degree in descending order
180+
*
181+
* @param graph the input graph
182+
* @return an array of integers representing the vertices sorted by degree
183+
*/
100184
private static Integer[] getSortedNodes(final Graph graph) {
101185
return IntStream.range(0, graph.getNumVertices()).boxed().sorted(Comparator.comparingInt(v -> - graph.getAdjacencyList(v).size())).toArray(Integer[] ::new);
102186
}
103187

188+
/**
189+
* Computes the colors already used by the adjacent vertices
190+
*
191+
* @param graph the input graph
192+
* @param vertex the vertex to check
193+
* @param colors the array of colors assigned to the vertices
194+
* @return an array of booleans representing the colors used by the adjacent vertices
195+
*/
104196
private static boolean[] computeUsedColors(final Graph graph, final int vertex, final int[] colors) {
105197
boolean[] usedColors = new boolean[graph.getNumVertices()];
106198
graph.getAdjacencyList(vertex).stream().map(neighbor -> colors[neighbor]).filter(color -> !isBlank(color)).forEach(color -> usedColors[color] = true);
107199
return usedColors;
108200
}
109201

202+
/**
203+
* Finds the first unused color
204+
*
205+
* @param usedColors the array of colors used by the adjacent vertices
206+
* @return the first unused color
207+
*/
110208
private static int firstUnusedColor(boolean[] usedColors) {
111209
return IntStream.range(0, usedColors.length).filter(color -> !usedColors[color]).findFirst().getAsInt();
112210
}

src/test/java/com/thealgorithms/datastructures/graphs/WelshPowellTest.java

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,26 +34,25 @@ void testCompleteGraph() {
3434
assertEquals(3, countDistinctColors(colors));
3535
}
3636

37-
// The following test originates from the following website : https://www.geeksforgeeks.org/welsh-powell-graph-colouring-algorithm/
3837
@Test
3938
void testComplexGraph() {
4039
int[][] edges = {
41-
{0, 7}, // A-H
42-
{0, 1}, // A-B
43-
{1, 3}, // B-D
44-
{2, 3}, // C-D
45-
{3, 8}, // D-I
46-
{3, 10}, // D-K
47-
{4, 10}, // E-K
48-
{4, 5}, // E-F
49-
{5, 6}, // F-G
50-
{6, 10}, // G-K
51-
{6, 7}, // G-H
52-
{7, 8}, // H-I
53-
{7, 9}, // H-J
54-
{7, 10}, // H-K
55-
{8, 9}, // I-J
56-
{9, 10}, // J-K
40+
{0, 7},
41+
{0, 1},
42+
{1, 3},
43+
{2, 3},
44+
{3, 8},
45+
{3, 10},
46+
{4, 10},
47+
{4, 5},
48+
{5, 6},
49+
{6, 10},
50+
{6, 7},
51+
{7, 8},
52+
{7, 9},
53+
{7, 10},
54+
{8, 9},
55+
{9, 10},
5756
};
5857

5958
final var graph = WelshPowell.makeGraph(11, edges); // 11 vertices from A (0) to K (10)
@@ -86,24 +85,35 @@ void testInvalidEdgeArray() {
8685

8786
@Test
8887
void testWithPreColoredVertex() {
89-
// Create a linear graph with 4 vertices and edges connecting them in sequence
9088
final var graph = WelshPowell.makeGraph(4, new int[][] {{0, 1}, {1, 2}, {2, 3}});
91-
92-
// Apply the Welsh-Powell coloring algorithm to the graph
9389
int[] colors = WelshPowell.findColoring(graph);
94-
95-
// Validate that the coloring is correct (no two adjacent vertices have the same color)
9690
assertTrue(isColoringValid(graph, colors));
97-
98-
// Check if the algorithm has used at least 2 colors (expected for a linear graph)
9991
assertTrue(countDistinctColors(colors) >= 2);
100-
101-
// Verify that all vertices have been assigned a color
10292
for (int color : colors) {
10393
assertTrue(color >= 0);
10494
}
10595
}
10696

97+
@Test
98+
void testLargeGraph() {
99+
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}};
100+
101+
final var graph = WelshPowell.makeGraph(16, edges); // 16 vertices
102+
int[] colors = WelshPowell.findColoring(graph);
103+
assertTrue(isColoringValid(graph, colors));
104+
assertEquals(3, countDistinctColors(colors)); // Expecting a maximum of 3 colors
105+
}
106+
107+
@Test
108+
void testStarGraph() {
109+
int[][] edges = {{0, 1}, {0, 2}, {0, 3}, {0, 4}};
110+
111+
final var graph = WelshPowell.makeGraph(5, edges); // 5 vertices in a star formation
112+
int[] colors = WelshPowell.findColoring(graph);
113+
assertTrue(isColoringValid(graph, colors));
114+
assertEquals(2, countDistinctColors(colors)); // Star graph can be colored with 2 colors
115+
}
116+
107117
private boolean isColoringValid(Graph graph, int[] colors) {
108118
if (Arrays.stream(colors).anyMatch(n -> n < 0)) {
109119
return false;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy