Skip to content

Commit 4edb802

Browse files
authored
chore: merge "feat: add Graph Coloring algorithms (TheAlgorithms#349)"
* feat: add Graph Coloring algorithms * chore(graph): styling & naming changes
1 parent bcb29db commit 4edb802

File tree

13 files changed

+489
-3
lines changed

13 files changed

+489
-3
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Being a contributor at The Algorithms, we request you to follow the points menti
1616

1717
- You did your own work.
1818
- No plagiarism is allowed. Any plagiarized work will not be merged.
19-
- Your work will be distributed under the [MIT License](https://github.com/TheAlgoritms/Go/blob/master/LICENSE) once your pull request has been merged.
19+
- Your work will be distributed under the [MIT License](https://github.com/TheAlgorithms/Go/blob/master/LICENSE) once your pull request has been merged.
2020
- Please follow the repository guidelines and standards mentioned below.
2121

2222
**New implementation** New implementations are welcome!

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute.
5757
* [Breadth First Search](./graph/breadthfirstsearch.go)
5858
* [Depth First Search](./graph/depthfirstsearch.go)
5959
* [Floyd Warshall](./graph/floydwarshall.go)
60-
60+
* [Coloring Algorithms](./graph/coloring)
61+
* [Using BFS](./graph/coloring/bfs.go)
62+
* [Using Backtracking](./graph/coloring/backtracking.go)
63+
* [Using Greedy Approach](./graph/coloring/greedy.go)
64+
6165
### Math
6266
* [Gcd](./math/gcd)
6367
* [Extended](./math/gcd/extended.go)

graph/coloring/backtracking.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// This file contains the graph coloring implementation using backtracking
2+
// Author(s): [Shivam](https://github.com/Shivam010)
3+
4+
package coloring
5+
6+
// ColorUsingBacktracking will return the Color of each vertex and the
7+
// total number of different colors used, using backtracking
8+
func (g *Graph) ColorUsingBacktracking() (map[int]Color, int) {
9+
vertexColors := make(map[int]Color, g.vertices)
10+
g.colorVertex(0, vertexColors)
11+
12+
colorsUsed := 0
13+
for _, cr := range vertexColors {
14+
if colorsUsed < int(cr) {
15+
colorsUsed = int(cr)
16+
}
17+
}
18+
return vertexColors, colorsUsed
19+
}
20+
21+
// colorVertex will try to color provided vertex, v
22+
func (g *Graph) colorVertex(v int, color map[int]Color) bool {
23+
// If all vertices are colored, the colors store will be completely filled.
24+
if len(color) == g.vertices {
25+
return true
26+
}
27+
28+
// As the upper bound of no. of colors is the no. of vertices in graph,
29+
// try assigning each color to the vertex v
30+
for cr := Color(1); cr <= Color(g.vertices); cr++ {
31+
// Use the color, cr for vertex, v if it is safe to use, by
32+
// checking its neighbours
33+
safe := true
34+
for nb := range g.edges[v] {
35+
// cr, color is not safe if color of nb, crnb is not equal to cr
36+
if crnb, ok := color[nb]; ok && crnb == cr {
37+
safe = false
38+
break
39+
}
40+
}
41+
if safe {
42+
color[v] = cr
43+
if g.colorVertex(v+1, color) {
44+
return true
45+
}
46+
delete(color, v)
47+
}
48+
}
49+
return false
50+
}

graph/coloring/backtracking_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// This file provides tests for coloring using backtracking.
2+
// Author(s): [Shivam](https://github.com/Shivam010)
3+
4+
package coloring_test
5+
6+
import (
7+
"strconv"
8+
"testing"
9+
)
10+
11+
func TestGraphColorUsingBacktracking(t *testing.T) {
12+
for i, tt := range getTestGraphs() {
13+
t.Run(strconv.Itoa(i), func(t *testing.T) {
14+
colorsOfVertices, colors := tt.Graph.ColorUsingBacktracking()
15+
if colors != tt.ColorsUsed {
16+
t.Errorf("ColorUsingBacktracking() return more number of colors: %v, want %v colors", colors, tt.ColorsUsed)
17+
}
18+
// check colors
19+
if err := tt.Graph.ValidateColorsOfVertex(colorsOfVertices); err != nil {
20+
t.Errorf("ColorUsingBacktracking() assigned colors are wrong, error = %v", err)
21+
}
22+
})
23+
}
24+
}

graph/coloring/bfs.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// This file contains the graph coloring implementation using BFS
2+
// Author(s): [Shivam](https://github.com/Shivam010)
3+
4+
package coloring
5+
6+
import "container/list"
7+
8+
// ColorUsingBFS will return the Color of each vertex and the
9+
// total number of different colors used, using BFS
10+
func (g *Graph) ColorUsingBFS() (map[int]Color, int) {
11+
// Initially all vertices will have same color
12+
vertexColors := make(map[int]Color, g.vertices)
13+
for i := 0; i < g.vertices; i++ {
14+
vertexColors[i] = 1
15+
}
16+
17+
visited := make(map[int]struct{})
18+
// Run BFS from each non-visited vertex
19+
for i := 0; i < g.vertices; i++ {
20+
if _, ok := visited[i]; ok {
21+
continue
22+
}
23+
visited[i] = struct{}{}
24+
25+
queue := list.New()
26+
queue.PushBack(i)
27+
28+
for queue.Len() != 0 {
29+
// front vertex in the queue
30+
frontNode := queue.Front()
31+
front := frontNode.Value.(int)
32+
queue.Remove(frontNode)
33+
34+
// Now, check all neighbours of front vertex, if they have same
35+
// color as that of front, change their color
36+
for nb := range g.edges[front] {
37+
if vertexColors[nb] == vertexColors[front] {
38+
vertexColors[nb]++
39+
}
40+
// if the neighbour is not already visited, add it to the queue
41+
if _, ok := visited[nb]; !ok {
42+
visited[nb] = struct{}{}
43+
queue.PushBack(nb)
44+
}
45+
}
46+
}
47+
}
48+
49+
colorsUsed := 0
50+
for _, cr := range vertexColors {
51+
if colorsUsed < int(cr) {
52+
colorsUsed = int(cr)
53+
}
54+
}
55+
return vertexColors, colorsUsed
56+
}

graph/coloring/bfs_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// This file provides tests for coloring using BFS.
2+
// Author(s): [Shivam](https://github.com/Shivam010)
3+
4+
package coloring_test
5+
6+
import (
7+
"strconv"
8+
"testing"
9+
)
10+
11+
func TestGraphColorUsingBFS(t *testing.T) {
12+
for i, tt := range getTestGraphs() {
13+
t.Run(strconv.Itoa(i), func(t *testing.T) {
14+
colorsOfVertices, colors := tt.Graph.ColorUsingBFS()
15+
if colors != tt.ColorsUsed {
16+
t.Errorf("ColorUsingBFS() return more number of colors: %v, want %v colors", colors, tt.ColorsUsed)
17+
}
18+
// check colors
19+
if err := tt.Graph.ValidateColorsOfVertex(colorsOfVertices); err != nil {
20+
t.Errorf("ColorUsingBFS() assigned colors are wrong, error = %v", err)
21+
}
22+
})
23+
}
24+
}

graph/coloring/doc.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Package coloring provides implementation of different graph coloring
2+
// algorithms, e.g. coloring using BFS, using Backtracking, using greedy
3+
// approach.
4+
// Author(s): [Shivam](https://github.com/Shivam010)
5+
package coloring

graph/coloring/graph.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// This file contains the simple structural implementation of undirected
2+
// graph, used in coloring algorithms.
3+
// Author(s): [Shivam](https://github.com/Shivam010)
4+
5+
package coloring
6+
7+
import "errors"
8+
9+
// Color provides a type for vertex color
10+
type Color int
11+
12+
// Graph provides a structure to store an undirected graph.
13+
// It is safe to use its empty object.
14+
type Graph struct {
15+
vertices int
16+
edges map[int]map[int]struct{}
17+
}
18+
19+
// AddVertex will add a new vertex in the graph, if the vertex already
20+
// exist it will do nothing
21+
func (g *Graph) AddVertex(v int) {
22+
if g.edges == nil {
23+
g.edges = make(map[int]map[int]struct{})
24+
}
25+
26+
// Check if vertex is present or not
27+
if _, ok := g.edges[v]; !ok {
28+
g.vertices++
29+
g.edges[v] = make(map[int]struct{})
30+
}
31+
}
32+
33+
// AddEdge will add a new edge between the provided vertices in the graph
34+
func (g *Graph) AddEdge(one, two int) {
35+
// Add vertices: one and two to the graph if they are not present
36+
g.AddVertex(one)
37+
g.AddVertex(two)
38+
39+
// and finally add the edges: one->two and two->one for undirected graph
40+
g.edges[one][two] = struct{}{}
41+
g.edges[two][one] = struct{}{}
42+
}
43+
44+
func (g *Graph) ValidateColorsOfVertex(colors map[int]Color) error {
45+
if g.vertices != len(colors) {
46+
return errors.New("coloring: not all vertices of graph are colored")
47+
}
48+
// check colors
49+
for vertex, neighbours := range g.edges {
50+
for nb := range neighbours {
51+
if colors[vertex] == colors[nb] {
52+
return errors.New("coloring: same colors of neighbouring vertex")
53+
}
54+
}
55+
}
56+
return nil
57+
}

graph/coloring/graph_test.go

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// This file provides tests for graph coloring validations.
2+
// Author(s): [Shivam](https://github.com/Shivam010)
3+
4+
package coloring_test
5+
6+
import (
7+
"github.com/TheAlgorithms/Go/graph/coloring"
8+
"strconv"
9+
"testing"
10+
)
11+
12+
type testGraph struct {
13+
Graph *coloring.Graph
14+
ColorsUsed int
15+
VertexColors map[int]coloring.Color
16+
}
17+
18+
func getTestGraphs() (list []*testGraph) {
19+
// Graph 0th:
20+
// 1---2
21+
// | / \
22+
// 4---3 0
23+
// Min number of colors required = 3
24+
g0 := &testGraph{
25+
Graph: &coloring.Graph{},
26+
ColorsUsed: 3,
27+
VertexColors: map[int]coloring.Color{
28+
1: 1, 4: 1, 0: 1,
29+
2: 2,
30+
3: 3,
31+
},
32+
}
33+
list = append(list, g0)
34+
g0.Graph.AddEdge(4, 3)
35+
g0.Graph.AddEdge(3, 1)
36+
g0.Graph.AddEdge(3, 2)
37+
g0.Graph.AddEdge(1, 2)
38+
g0.Graph.AddEdge(2, 0)
39+
40+
// Graph 1st:
41+
// 1---2
42+
// | / |
43+
// 4---3---0
44+
// Min number of colors required = 3
45+
g1 := &testGraph{
46+
Graph: &coloring.Graph{},
47+
ColorsUsed: 3,
48+
VertexColors: map[int]coloring.Color{
49+
1: 1, 4: 1, 0: 1,
50+
2: 2,
51+
3: 3,
52+
},
53+
}
54+
list = append(list, g1)
55+
g1.Graph.AddEdge(4, 3)
56+
g1.Graph.AddEdge(3, 1)
57+
g1.Graph.AddEdge(3, 2)
58+
g1.Graph.AddEdge(1, 2)
59+
g1.Graph.AddEdge(2, 0)
60+
g1.Graph.AddEdge(3, 0)
61+
62+
// Graph 2nd:
63+
// 1---2
64+
// |
65+
// 4---3 0
66+
// Min number of colors required = 2
67+
g2 := &testGraph{
68+
Graph: &coloring.Graph{},
69+
ColorsUsed: 2,
70+
VertexColors: map[int]coloring.Color{
71+
1: 1, 4: 1, 0: 1,
72+
2: 2, 3: 2,
73+
},
74+
}
75+
list = append(list, g2)
76+
g2.Graph.AddVertex(0)
77+
g2.Graph.AddEdge(4, 3)
78+
g2.Graph.AddEdge(3, 1)
79+
g2.Graph.AddEdge(1, 2)
80+
81+
// Graph 3rd:
82+
// 1---2 4
83+
// | | |
84+
// 0---3 5
85+
// Min number of colors required = 2
86+
g3 := &testGraph{
87+
Graph: &coloring.Graph{},
88+
ColorsUsed: 2,
89+
VertexColors: map[int]coloring.Color{
90+
1: 1, 3: 1, 4: 1,
91+
0: 2, 2: 2, 5: 2,
92+
},
93+
}
94+
list = append(list, g3)
95+
g3.Graph.AddEdge(0, 3)
96+
g3.Graph.AddEdge(1, 2)
97+
g3.Graph.AddEdge(1, 0)
98+
g3.Graph.AddEdge(3, 2)
99+
g3.Graph.AddEdge(4, 5)
100+
101+
// Graph 4th:
102+
// Completely Connected graph of vertex 4
103+
// Min number of colors required = 2
104+
g4 := &testGraph{
105+
Graph: &coloring.Graph{},
106+
ColorsUsed: 4,
107+
VertexColors: map[int]coloring.Color{
108+
0: 1, 1: 2, 2: 3, 4: 4,
109+
},
110+
}
111+
list = append(list, g4)
112+
for i := 0; i < 4; i++ {
113+
for j := i + 1; j < 4; j++ {
114+
g4.Graph.AddEdge(i, j)
115+
}
116+
}
117+
118+
return
119+
}
120+
121+
func TestGraph_ValidateColorsOfVertex(t *testing.T) {
122+
for i, tt := range getTestGraphs() {
123+
t.Run(strconv.Itoa(i), func(t *testing.T) {
124+
if err := tt.Graph.ValidateColorsOfVertex(tt.VertexColors); err != nil {
125+
t.Errorf("ValidateColorsOfVertex() error = %v, wantErr nil", err)
126+
}
127+
})
128+
}
129+
}
130+
131+
func getTestGraphsForNegativeTests() (list []*testGraph) {
132+
list = getTestGraphs()
133+
list[0].VertexColors = nil
134+
list[1].VertexColors = map[int]coloring.Color{}
135+
for v := range list[2].VertexColors {
136+
in := len(list[2].VertexColors) - v - 1
137+
list[2].VertexColors[v] = list[2].VertexColors[in]
138+
}
139+
for v := range list[3].VertexColors {
140+
list[3].VertexColors[v] = 1
141+
}
142+
return list[:4]
143+
}
144+
145+
func TestGraphValidateColorsOfVertex_Negative(t *testing.T) {
146+
for i, tt := range getTestGraphsForNegativeTests() {
147+
t.Run(strconv.Itoa(i), func(t *testing.T) {
148+
if err := tt.Graph.ValidateColorsOfVertex(tt.VertexColors); err == nil {
149+
t.Errorf("ValidateColorsOfVertex() error = nil, want some err")
150+
}
151+
})
152+
}
153+
}

0 commit comments

Comments
 (0)