tarjans-algorithm.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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)" %
  36. (node, successor))
  37. # Successor has not yet been visited; recurse on it
  38. strongconnect(successor, index_counter)
  39. lowlinks[node] = min(lowlinks[node], lowlinks[successor])
  40. elif successor in stack:
  41. # else:
  42. print("successor in stack: %s -> %s" % (node, successor))
  43. # the successor is in the stack and hence in the
  44. # current strongly connected component (SCC)
  45. lowlinks[node] = min(lowlinks[node], index[successor])
  46. else:
  47. print("This happens sometimes. node: %s, successor: %s" %
  48. (node, successor))
  49. print("Lowlinks: %s" % lowlinks)
  50. print("stack: %s" % stack)
  51. # If `node` is a root node, pop the stack and generate an SCC
  52. if lowlinks[node] == index[node]:
  53. print("Got root node: %s (index/lowlink: %i)" %
  54. (node, lowlinks[node]))
  55. connected_component = []
  56. while True:
  57. successor = stack.pop()
  58. print("pop: %s" % successor)
  59. connected_component.append(successor)
  60. if successor == node:
  61. break
  62. component = tuple(connected_component)
  63. # storing the result
  64. result.append(component)
  65. else:
  66. print("Node: %s, lowlink: %i, index: %i" %
  67. (node, lowlinks[node], index[node]))
  68. for node in graph:
  69. if node not in lowlinks:
  70. strongconnect(node, index_counter)
  71. return result
  72. graph = {'a': ['b'],
  73. 'b': ['c'],
  74. 'c': ['d', 'e'],
  75. 'd': ['a', 'e', 'h'],
  76. 'e': ['c', 'f'],
  77. 'f': ['g', 'i'],
  78. 'g': ['h', 'f'],
  79. 'h': ['j'],
  80. 'i': ['g', 'f'],
  81. 'j': ['i'],
  82. 'k': [],
  83. 'h': []}
  84. print strongly_connected_components(graph)