@@ -65,77 +65,7 @@ def topological_sort(graph: dict[int, list[int]]) -> list[int] | None:
6565 return topo_order # valid topological ordering
6666
6767
68- def _topological_sort_list_queue (graph : dict [int , list [int ]]) -> list [int ] | None :
69- """
70- Pre-optimization implementation of Kahn's topological sort using list.pop(0).
71-
72- Used as a baseline for benchmark comparison against deque.popleft().
73- """
74- indegree = [0 ] * len (graph )
75- queue = []
76- topo_order = []
77- processed_vertices_count = 0
78-
79- for values in graph .values ():
80- for i in values :
81- indegree [i ] += 1
82-
83- for i in range (len (indegree )):
84- if indegree [i ] == 0 :
85- queue .append (i )
86-
87- while queue :
88- vertex = queue .pop (0 )
89- processed_vertices_count += 1
90- topo_order .append (vertex )
91-
92- for neighbor in graph [vertex ]:
93- indegree [neighbor ] -= 1
94- if indegree [neighbor ] == 0 :
95- queue .append (neighbor )
96-
97- if processed_vertices_count != len (graph ):
98- return None
99- return topo_order
100-
101-
102- def benchmark () -> None :
103- """
104- Benchmark comparing topological_sort() (using deque.popleft) against
105- the pre-optimization baseline _topological_sort_list_queue() (using list.pop(0)).
106-
107- Demonstrates the performance improvement of O(1) queue operations in
108- Kahn's algorithm on a graph with a large number of zero-indegree vertices.
109- """
110- from timeit import timeit
111-
112- num_sources = 30_000
113- graph = {i : [num_sources ] for i in range (num_sources )}
114- graph [num_sources ] = []
115-
116- # Verify correctness: both implementations produce valid topological sorts
117- old_result = _topological_sort_list_queue (graph )
118- new_result = topological_sort (graph )
119- assert old_result is not None and new_result is not None
120- assert len (old_result ) == len (new_result ) == num_sources + 1
121- assert set (old_result ) == set (new_result )
122-
123- runs = 5
124- old_time = timeit (lambda : _topological_sort_list_queue (graph ), number = runs )
125- new_time = timeit (lambda : topological_sort (graph ), number = runs )
126-
127- print (
128- f"Benchmark results for topological_sort with { num_sources } vertices "
129- f"over { runs } runs:"
130- )
131- print (f"Pre-optimization (list.pop(0)): { old_time :.5f} seconds" )
132- print (f"Current (deque.popleft): { new_time :.5f} seconds" )
133- if new_time > 0 :
134- print (f"Speedup ratio: { old_time / new_time :.2f} x faster" )
135-
136-
13768if __name__ == "__main__" :
13869 import doctest
13970
14071 doctest .testmod ()
141- benchmark ()
0 commit comments