Skip to content

Commit 4f10cbb

Browse files
Modified docs,test of topological sort algorithm
1 parent c2adc3b commit 4f10cbb

File tree

1 file changed

+138
-37
lines changed

1 file changed

+138
-37
lines changed

graph/topological_sort.cpp

Lines changed: 138 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,151 @@
1-
#include <algorithm>
2-
#include <iostream>
3-
#include <vector>
4-
5-
int number_of_vertices,
6-
number_of_edges; // For number of Vertices (V) and number of edges (E)
7-
std::vector<std::vector<int>> graph;
8-
std::vector<bool> visited;
9-
std::vector<int> topological_order;
10-
11-
void dfs(int v) {
12-
visited[v] = true;
13-
for (int u : graph[v]) {
14-
if (!visited[u]) {
15-
dfs(u);
1+
/**
2+
* @file
3+
* @brief [Topological Sort
4+
* Algorithm](https://en.wikipedia.org/wiki/Topological_sorting)
5+
* @details
6+
* Topological sorting of a directed graph is a linear ordering or its vertices
7+
* such that for every directed edge (u,v) from vertex u to vertex v, u comes
8+
* before v in the oredering.
9+
*
10+
* A topological sort is possible only in a directed acyclic graph (DAG).
11+
* This file contains code of finding topological sort using Kahn's Algorithm
12+
* which involves using Depth First Search technique
13+
*/
14+
15+
#include <algorithm> // For std::reverse
16+
#include <cassert> // For assert
17+
#include <iostream> // For IO operations
18+
#include <stack> // For std::stack
19+
#include <stdexcept> // For std::invalid_argument
20+
#include <vector> // For std::vector
21+
22+
/**
23+
* @namespace graph
24+
* @brief Graph algorithms
25+
*/
26+
namespace graph {
27+
28+
/**
29+
* @brief Function that add edge between two nodes or vertices of graph
30+
* @param u any node or vertex of graph
31+
* @param v any node or vertex of graph
32+
* @returns None
33+
*/
34+
void addEdge(std::vector<std::vector<int>>& adj, int u, int v) {
35+
adj[u].push_back(v);
36+
}
37+
38+
/**
39+
* @brief Function to perform Depth First Search on the graph
40+
* @param v starting vertex for depth first search
41+
* @param vistied array representing if a node is visited
42+
* @param graph adjecancy list of the graph
43+
* @param s stack containing the vertex of topological sort
44+
* @returns None
45+
*/
46+
void dfs(int v, std::vector<int>& visited, std::vector<std::vector<int>>& graph,
47+
std::stack<int>& s) {
48+
visited[v] = 1;
49+
for (int i = 0; i < graph[v].size(); i++) {
50+
int neighbour = graph[v][i];
51+
if (!visited[neighbour]) {
52+
dfs(neighbour, visited, graph, s);
1653
}
1754
}
18-
topological_order.push_back(v);
55+
s.push(v);
1956
}
2057

21-
void topological_sort() {
22-
visited.assign(number_of_vertices, false);
23-
topological_order.clear();
24-
for (int i = 0; i < number_of_vertices; ++i) {
58+
/**
59+
* @brief Function to get the topological sort of the graph
60+
* @param graph adjecancy list of the graph
61+
* @param n number of nodes in the graph
62+
*/
63+
std::vector<int> topological_sort(std::vector<std::vector<int>>& graph, int n) {
64+
std::vector<int> visited(n, 0);
65+
std::stack<int> s;
66+
for (int i = 0; i < n; i++) {
2567
if (!visited[i]) {
26-
dfs(i);
68+
dfs(i, visited, graph, s);
2769
}
2870
}
29-
reverse(topological_order.begin(), topological_order.end());
71+
std::vector<int> ans;
72+
while (!s.empty()) {
73+
int elem = s.top();
74+
s.pop();
75+
ans.push_back(elem);
76+
}
77+
if (ans.size() < n) { // Cycle detected
78+
throw std::invalid_argument("cycle present in graph");
79+
}
80+
return ans;
3081
}
31-
int main() {
32-
std::cout
33-
<< "Enter the number of vertices and the number of directed edges\n";
34-
std::cin >> number_of_vertices >> number_of_edges;
35-
int x = 0, y = 0;
36-
graph.resize(number_of_vertices, std::vector<int>());
37-
for (int i = 0; i < number_of_edges; ++i) {
38-
std::cin >> x >> y;
39-
x--, y--; // to convert 1-indexed to 0-indexed
40-
graph[x].push_back(y);
82+
} // namespace graph
83+
84+
/**
85+
* @brief Self-test implementation
86+
* @returns void
87+
*/
88+
static void test() {
89+
// Test 1;
90+
std::cout << "Testing for graph 1\n";
91+
int n_1 = 6;
92+
std::vector<std::vector<int>> adj_1(n_1);
93+
graph::addEdge(adj_1, 4, 0);
94+
graph::addEdge(adj_1, 5, 0);
95+
graph::addEdge(adj_1, 5, 2);
96+
graph::addEdge(adj_1, 2, 3);
97+
graph::addEdge(adj_1, 3, 1);
98+
graph::addEdge(adj_1, 4, 1);
99+
std::vector<int> ans_1 = graph::topological_sort(adj_1, n_1);
100+
std::vector<int> expected_1 = {5, 4, 2, 3, 1, 0};
101+
std::cout << "Topological Sorting Order: ";
102+
for (int i : ans_1) {
103+
std::cout << i << " ";
41104
}
42-
topological_sort();
43-
std::cout << "Topological Order : \n";
44-
for (int v : topological_order) {
45-
std::cout << v + 1
46-
<< ' '; // converting zero based indexing back to one based.
105+
std::cout << '\n';
106+
assert(ans_1 == expected_1);
107+
std::cout << "Test Passed\n\n";
108+
109+
// Test 2
110+
std::cout << "Testing for graph 2\n";
111+
int n_2 = 5;
112+
std::vector<std::vector<int>> adj_2(n_2);
113+
graph::addEdge(adj_2, 0, 1);
114+
graph::addEdge(adj_2, 0, 2);
115+
graph::addEdge(adj_2, 1, 2);
116+
graph::addEdge(adj_2, 2, 3);
117+
graph::addEdge(adj_2, 1, 3);
118+
graph::addEdge(adj_2, 2, 4);
119+
std::vector<int> ans_2 = graph::topological_sort(adj_2, n_2);
120+
std::vector<int> expected_2 = {0, 1, 2, 4, 3};
121+
std::cout << "Topological Sorting Order: ";
122+
for (int i : ans_2) {
123+
std::cout << i << " ";
47124
}
48125
std::cout << '\n';
126+
assert(ans_2 == expected_2);
127+
std::cout << "Test Passed\n\n";
128+
129+
// Test 3 - Graph with cycle
130+
std::cout << "Testing for graph 3\n";
131+
int n_3 = 3;
132+
std::vector<std::vector<int>> adj_3(n_3);
133+
graph::addEdge(adj_3, 0, 1);
134+
graph::addEdge(adj_3, 1, 2);
135+
graph::addEdge(adj_3, 2, 0);
136+
try {
137+
graph::topological_sort(adj_3, n_3);
138+
} catch (std::invalid_argument& err) {
139+
assert(std::string(err.what()) == "cycle detected in graph");
140+
}
141+
std::cout << "Test Passed \n";
142+
}
143+
144+
/**
145+
* @brief Main function
146+
* @returns 0 on exit
147+
*/
148+
int main() {
149+
test();
49150
return 0;
50151
}

0 commit comments

Comments
 (0)