* lib/tsort.rb (TSort.each_strongly_connected_component_from):

Extracted from TSort#each_strongly_connected_component_from.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43326 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
akr 2013-10-17 03:32:15 +00:00
parent 209376034f
commit ed6231195b
4 changed files with 44 additions and 3 deletions

View File

@ -1,3 +1,8 @@
Thu Oct 17 12:30:16 2013 Tanaka Akira <akr@fsij.org>
* lib/tsort.rb (TSort.each_strongly_connected_component_from):
Extracted from TSort#each_strongly_connected_component_from.
Thu Oct 17 11:07:06 2013 Eric Hodel <drbrain@segment7.net> Thu Oct 17 11:07:06 2013 Eric Hodel <drbrain@segment7.net>
* lib/rubygems: Update to RubyGems master 941c21a. Changes: * lib/rubygems: Update to RubyGems master 941c21a. Changes:

4
NEWS
View File

@ -244,6 +244,10 @@ with all sufficient information, see the ChangeLog file.
inside the block, by default, unless the exception class is given inside the block, by default, unless the exception class is given
explicitly. explicitly.
* TSort
* New methods:
* TSort.each_strongly_connected_component_from
* WEBrick * WEBrick
* The body of a response may now be a StringIO or other IO-like that responds * The body of a response may now be a StringIO or other IO-like that responds
to #readpartial and #read. to #readpartial and #read.

View File

@ -195,18 +195,40 @@ module TSort
# #
# #each_strongly_connected_component_from doesn't call #tsort_each_node. # #each_strongly_connected_component_from doesn't call #tsort_each_node.
# #
def each_strongly_connected_component_from(node, id_map={}, stack=[]) # :yields: nodes def each_strongly_connected_component_from(node, id_map={}, stack=[], &block) # :yields: nodes
TSort.each_strongly_connected_component_from(node, method(:tsort_each_child), id_map, stack, &block)
end
# Iterates over strongly connected components in a graph.
# The graph is represented by _node_ and _each_child_.
#
# _node_ is the first node.
# _each_child_ should have +call+ method which takes a node argument
# and yields for each adjacent node.
#
# Return value is unspecified.
#
# #TSort.each_strongly_connected_component_from is a class method and
# it doesn't need a class to represent a graph which includes TSort.
#
# graph = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
# each_child = lambda {|n, &b| graph[n].each(&b) }
# TSort.each_strongly_connected_component_from(1, each_child) {|scc|
# p scc #=> [4], [2, 3], [1]
# }
#
def TSort.each_strongly_connected_component_from(node, each_child, id_map={}, stack=[]) # :yields: nodes
minimum_id = node_id = id_map[node] = id_map.size minimum_id = node_id = id_map[node] = id_map.size
stack_length = stack.length stack_length = stack.length
stack << node stack << node
tsort_each_child(node) {|child| each_child.call(node) {|child|
if id_map.include? child if id_map.include? child
child_id = id_map[child] child_id = id_map[child]
minimum_id = child_id if child_id && child_id < minimum_id minimum_id = child_id if child_id && child_id < minimum_id
else else
sub_minimum_id = sub_minimum_id =
each_strongly_connected_component_from(child, id_map, stack) {|c| TSort.each_strongly_connected_component_from(child, each_child, id_map, stack) {|c|
yield c yield c
} }
minimum_id = sub_minimum_id if sub_minimum_id < minimum_id minimum_id = sub_minimum_id if sub_minimum_id < minimum_id

View File

@ -40,5 +40,15 @@ class TSortTest < Test::Unit::TestCase # :nodoc:
assert_equal([[0], [1]], assert_equal([[0], [1]],
a.strongly_connected_components.map {|nodes| nodes.sort}) a.strongly_connected_components.map {|nodes| nodes.sort})
end end
def test_noclass
g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
each_child = lambda {|n, &b| g[n].each(&b) }
r = []
TSort.each_strongly_connected_component_from(1, each_child) {|scc|
r << scc
}
assert_equal([[4], [2, 3], [1]], r)
end
end end