http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm
http://en.algoritmy.net/article/44220/Tarjans-algorithm
我无法在我的 Ruby 版本的 Tarjan 强连接组件算法中找出这个错误。我得到了 Kosaraju–Sharir 算法,我的 Ruby 中的 Tarjan 算法适用于一些图。但它没有连接应该连接的2个组件---“10”和“11,12,9”
输入文件是这个有向图:http ://algs4.cs.princeton.edu/42directed/tinyDG.txt
expected: [["1"], ["0", "2", "3", "4", "5"], ["10", "11", "12", "9"], ["6", "8"], ["7"]]
got: [["1"], ["0", "2", "3", "4", "5"], ["10"], ["11", "12", "9"], ["6", "8"], ["7"]]
在这个尝试制作单个组件的最终循环中,它以“10”(堆栈上的最后一项)开始,但当前顶点(“父级”)也是“10”!这使得循环切断“10”作为一个单独的组件。为什么栈上的最新项与父节点相同?在我们收集 ["12", "11", "9"...then "10"] 之后,我希望“10”只会出现在组件的末尾。因为“10”首先出现,而不是最后出现,所以我们遇到了这个问题。我如何解决它?
begin
last_stack_item = stack.pop
component << last_stack_item.name
end while last_stack_item != parent # we're back at the root
我的红宝石代码:
# Tarjan's algorithm to find all strongly connected components (SCCs)
def scc_tarjan
index = 0 # numbers nodes consecutively in the order discovered
stack, scc, vertices = [], [], []
# create new Struct, if not already defined
if Struct::const_defined?("TarjanVertex")
Struct.const_get("TarjanVertex")
else
Struct.new("TarjanVertex", :name, :index, :lowlink)
end
adj_lists.each do |v|
# -1 means vertex is unvisited
vertex = Struct::TarjanVertex.new(v.name, -1, -1)
vertices << vertex # array of all TarjanVertex objects in graph
end
vertices.each do |vertex|
tarjan_dfs(vertex, scc, stack, index, vertices) if vertex.index == -1
end
# return nested array of all SCCs in graph
scc
end
def tarjan_dfs(parent, scc, stack, index, vertices)
# Set depth index for vertex to smallest unused index
parent.index = index
# lowlink is roughly the smallest index of any node known to be reachable from the vertex
parent.lowlink = index
index += 1
stack << parent
# loop through all vertices connected to parent
adj_vertices(parent.name, adj_lists).each do |adj_vertex|
# since adj_vertices returns array of strings,
# must convert to TarjanVertex objects
child = vertices.select {|v| v.name == adj_vertex}.first
if child.index == -1 # if child vertex not yet visited
tarjan_dfs(child, scc, stack, index, vertices) # recurse on child
# change parent's lowlink to smaller lowlink of parent and child)
parent.lowlink = [parent.lowlink, child.lowlink].min
# vertex points to earlier (already visited) one in stack,
# with lower index. thus it's the current SCC
elsif stack.include?(child)
parent.lowlink = [parent.lowlink, child.index].min
end
end
# if a vertex's lowlink = its index here, this # cannot go any lower.
# vertex MUST be root of the SCC.
if parent.lowlink == parent.index
component = [] # a single SCC
# pop off entire SCC, one vertex at a time
begin
last_stack_item = stack.pop
component << last_stack_item.name
end while last_stack_item != parent # we're back at the root
scc << component.sort # done with a single SCC
end
end