Skip to content

Commit e625a9f

Browse files
authored
Kahn's algorithm for topological sort (#286)
1 parent 8fef63a commit e625a9f

File tree

3 files changed

+100
-4
lines changed

3 files changed

+100
-4
lines changed

pydatastructs/graphs/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
minimum_spanning_tree_parallel,
1515
strongly_connected_components,
1616
depth_first_search,
17-
shortest_paths
17+
shortest_paths,
18+
topological_sort
1819
)
1920

2021
__all__.extend(algorithms.__all__)

pydatastructs/graphs/algorithms.py

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Contains all the algorithms associated with graph
2+
Contains algorithms associated with graph
33
data structure.
44
"""
55
from collections import deque
@@ -18,7 +18,8 @@
1818
'minimum_spanning_tree_parallel',
1919
'strongly_connected_components',
2020
'depth_first_search',
21-
'shortest_paths'
21+
'shortest_paths',
22+
'topological_sort'
2223
]
2324

2425
Stack = Queue = deque
@@ -725,3 +726,73 @@ def _bellman_ford_adjacency_list(graph: Graph, source: str, target: str) -> tupl
725726
return (distances, predecessor)
726727

727728
_bellman_ford_adjacency_matrix = _bellman_ford_adjacency_list
729+
730+
def topological_sort(graph: Graph, algorithm: str) -> list:
731+
"""
732+
Performs topological sort on the given graph using given algorithm.
733+
734+
Parameters
735+
==========
736+
737+
graph: Graph
738+
The graph under consideration.
739+
algorithm: str
740+
The algorithm to be used.
741+
Currently, following are supported,
742+
'kahn' -> Kahn's algorithm as given in [1].
743+
744+
Returns
745+
=======
746+
747+
list
748+
The list of topologically sorted vertices.
749+
750+
Examples
751+
========
752+
753+
>>> from pydatastructs import Graph, AdjacencyListGraphNode, topological_sort
754+
>>> v_1 = AdjacencyListGraphNode('v_1')
755+
>>> v_2 = AdjacencyListGraphNode('v_2')
756+
>>> graph = Graph(v_1, v_2)
757+
>>> graph.add_edge('v_1', 'v_2')
758+
>>> topological_sort(graph, 'kahn')
759+
['v_1', 'v_2']
760+
761+
References
762+
==========
763+
764+
.. [1] https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm
765+
"""
766+
import pydatastructs.graphs.algorithms as algorithms
767+
func = "_" + algorithm + "_" + graph._impl
768+
if not hasattr(algorithms, func):
769+
raise NotImplementedError(
770+
"Currently %s algorithm isn't implemented for "
771+
"performing topological sort on %s graphs."%(algorithm, graph._impl))
772+
return getattr(algorithms, func)(graph)
773+
774+
def _kahn_adjacency_list(graph: Graph) -> list:
775+
S = set(graph.vertices)
776+
in_degree = dict()
777+
for u in graph.vertices:
778+
for v in graph.neighbors(u):
779+
if v.name not in in_degree:
780+
in_degree[v.name] = 0
781+
in_degree[v.name] += 1
782+
if v.name in S:
783+
S.remove(v.name)
784+
785+
L = []
786+
while S:
787+
n = S.pop()
788+
L.append(n)
789+
for m in graph.neighbors(n):
790+
graph.remove_edge(n, m.name)
791+
in_degree[m.name] -= 1
792+
if in_degree[m.name] == 0:
793+
S.add(m.name)
794+
in_degree.pop(m.name)
795+
796+
if in_degree:
797+
raise ValueError("Graph is not acyclic.")
798+
return L

pydatastructs/graphs/tests/test_algorithms.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from pydatastructs import (breadth_first_search, Graph,
22
breadth_first_search_parallel, minimum_spanning_tree,
33
minimum_spanning_tree_parallel, strongly_connected_components,
4-
depth_first_search, shortest_paths)
4+
depth_first_search, shortest_paths, topological_sort)
55
from pydatastructs.utils.raises_util import raises
66

77
def test_breadth_first_search():
@@ -289,3 +289,27 @@ def _test_shortest_paths(ds, algorithm):
289289

290290
_test_shortest_paths("List", 'bellman_ford')
291291
_test_shortest_paths("Matrix", 'bellman_ford')
292+
293+
def test_topological_sort():
294+
295+
def _test_topological_sort(ds, algorithm):
296+
import pydatastructs.utils.misc_util as utils
297+
GraphNode = getattr(utils, "Adjacency" + ds + "GraphNode")
298+
vertices = [GraphNode('2'), GraphNode('3'), GraphNode('5'),
299+
GraphNode('7'), GraphNode('8'), GraphNode('10'),
300+
GraphNode('11'), GraphNode('9')]
301+
302+
graph = Graph(*vertices)
303+
graph.add_edge('5', '11')
304+
graph.add_edge('7', '11')
305+
graph.add_edge('7', '8')
306+
graph.add_edge('3', '8')
307+
graph.add_edge('3', '10')
308+
graph.add_edge('11', '2')
309+
graph.add_edge('11', '9')
310+
graph.add_edge('11', '10')
311+
graph.add_edge('8', '9')
312+
l = topological_sort(graph, algorithm)
313+
assert all([(l1 in l[0:3]) for l1 in ('3', '5', '7')] +
314+
[(l2 in l[3:5]) for l2 in ('8', '11')] +
315+
[(l3 in l[5:]) for l3 in ('10', '9', '2')])

0 commit comments

Comments
 (0)