tarjans-algorithm.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. def strongly_connected_components(graph):
  2. """
  3. Tarjan's Algorithm (named for its discoverer, Robert Tarjan) is a
  4. graph theory algorithm for finding the strongly connected
  5. components of a graph.
  6. Based on: http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
  7. @author: Dries Verdegem, some minor edits by Martin Thoma
  8. @source: http://www.logarithmic.net/pfh/blog/01208083168
  9. """
  10. index_counter = 0
  11. stack = []
  12. lowlinks = {}
  13. index = {}
  14. result = []
  15. def strongconnect(node, index_counter):
  16. print("Start with node: %s###########################" % node)
  17. # set the depth index for this node to the smallest unused index
  18. print("lowlinks:\t%s" % lowlinks)
  19. print("index:\t%s" % index)
  20. print("stack:\t%s" % stack)
  21. index[node] = index_counter
  22. lowlinks[node] = index_counter
  23. index_counter += 1
  24. stack.append(node)
  25. # Consider successors of `node`
  26. try:
  27. successors = graph[node]
  28. except:
  29. successors = []
  30. # Depth first search
  31. for successor in successors:
  32. # Does the current node point to a node that was already
  33. # visited?
  34. if successor not in lowlinks:
  35. print("successor not in lowlinks: %s -> %s (node, successor)" % (node, successor))
  36. # Successor has not yet been visited; recurse on it
  37. strongconnect(successor, index_counter)
  38. lowlinks[node] = min(lowlinks[node],lowlinks[successor])
  39. elif successor in stack:
  40. #else:
  41. print("successor in stack: %s -> %s" % (node, successor));
  42. # the successor is in the stack and hence in the
  43. # current strongly connected component (SCC)
  44. lowlinks[node] = min(lowlinks[node],index[successor])
  45. else:
  46. print("This happens sometimes. node: %s, successor: %s" % (node, successor))
  47. print("Lowlinks: %s" %lowlinks)
  48. print("stack: %s" % stack)
  49. # If `node` is a root node, pop the stack and generate an SCC
  50. if lowlinks[node] == index[node]:
  51. print("Got root node: %s (index/lowlink: %i)" % (node, lowlinks[node]))
  52. connected_component = []
  53. while True:
  54. successor = stack.pop()
  55. print("pop: %s" % successor)
  56. connected_component.append(successor)
  57. if successor == node: break
  58. component = tuple(connected_component)
  59. # storing the result
  60. result.append(component)
  61. else:
  62. print("Node: %s, lowlink: %i, index: %i" % (node, lowlinks[node], index[node]))
  63. for node in graph:
  64. if node not in lowlinks:
  65. strongconnect(node, index_counter)
  66. return result
  67. graph = {'a': ['b'],
  68. 'b': ['c'],
  69. 'c': ['d', 'e'],
  70. 'd': ['a', 'e', 'h'],
  71. 'e': ['c', 'f'],
  72. 'f': ['g', 'i'],
  73. 'g': ['h', 'f'],
  74. 'h': ['j'],
  75. 'i': ['g', 'f'],
  76. 'j': ['i'],
  77. 'k': [],
  78. 'h': []}
  79. print strongly_connected_components(graph)