mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* lib/tsort.rb (TSort.tsort): Extracted from TSort#tsort.
(TSort.tsort_each): Extracted from TSort#tsort_each. (TSort.strongly_connected_components): Extracted from TSort#strongly_connected_components. (TSort.each_strongly_connected_component): Extracted from TSort#each_strongly_connected_component. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43342 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
b0c19be284
commit
4c5bfb9fbd
4 changed files with 170 additions and 9 deletions
|
@ -1,3 +1,12 @@
|
||||||
|
Fri Oct 18 00:57:07 2013 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
|
* lib/tsort.rb (TSort.tsort): Extracted from TSort#tsort.
|
||||||
|
(TSort.tsort_each): Extracted from TSort#tsort_each.
|
||||||
|
(TSort.strongly_connected_components): Extracted from
|
||||||
|
TSort#strongly_connected_components.
|
||||||
|
(TSort.each_strongly_connected_component): Extracted from
|
||||||
|
TSort#each_strongly_connected_component.
|
||||||
|
|
||||||
Thu Oct 17 18:50:08 2013 Koichi Sasada <ko1@atdot.net>
|
Thu Oct 17 18:50:08 2013 Koichi Sasada <ko1@atdot.net>
|
||||||
|
|
||||||
* gc.c (CALC_EXACT_MALLOC_SIZE_CHECK_OLD_SIZE): introduced.
|
* gc.c (CALC_EXACT_MALLOC_SIZE_CHECK_OLD_SIZE): introduced.
|
||||||
|
|
4
NEWS
4
NEWS
|
@ -246,6 +246,10 @@ with all sufficient information, see the ChangeLog file.
|
||||||
|
|
||||||
* TSort
|
* TSort
|
||||||
* New methods:
|
* New methods:
|
||||||
|
* TSort.tsort
|
||||||
|
* TSort.tsort_each
|
||||||
|
* TSort.strongly_connected_components
|
||||||
|
* TSort.each_strongly_connected_component
|
||||||
* TSort.each_strongly_connected_component_from
|
* TSort.each_strongly_connected_component_from
|
||||||
|
|
||||||
* WEBrick
|
* WEBrick
|
||||||
|
|
118
lib/tsort.rb
118
lib/tsort.rb
|
@ -145,8 +145,34 @@ module TSort
|
||||||
# p graph.tsort # raises TSort::Cyclic
|
# p graph.tsort # raises TSort::Cyclic
|
||||||
#
|
#
|
||||||
def tsort
|
def tsort
|
||||||
|
each_node = method(:tsort_each_node)
|
||||||
|
each_child = method(:tsort_each_child)
|
||||||
|
TSort.tsort(each_node, each_child)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns a topologically sorted array of nodes.
|
||||||
|
# The array is sorted from children to parents, i.e.
|
||||||
|
# the first element has no child and the last node has no parent.
|
||||||
|
#
|
||||||
|
# The graph is represented by _each_node_ and _each_child_.
|
||||||
|
# _each_node_ should have +call+ method which yields for each node in the graph.
|
||||||
|
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
|
||||||
|
#
|
||||||
|
# If there is a cycle, TSort::Cyclic is raised.
|
||||||
|
#
|
||||||
|
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
|
||||||
|
# each_node = lambda {|&b| g.each_key(&b) }
|
||||||
|
# each_child = lambda {|n, &b| g[n].each(&b) }
|
||||||
|
# p TSort.tsort(each_node, each_child) #=> [4, 2, 3, 1]
|
||||||
|
#
|
||||||
|
# g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
|
||||||
|
# each_node = lambda {|&b| g.each_key(&b) }
|
||||||
|
# each_child = lambda {|n, &b| g[n].each(&b) }
|
||||||
|
# p TSort.tsort(each_node, each_child) # raises TSort::Cyclic
|
||||||
|
#
|
||||||
|
def TSort.tsort(each_node, each_child)
|
||||||
result = []
|
result = []
|
||||||
tsort_each {|element| result << element}
|
TSort.tsort_each(each_node, each_child) {|element| result << element}
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -173,8 +199,29 @@ module TSort
|
||||||
# # 3
|
# # 3
|
||||||
# # 1
|
# # 1
|
||||||
#
|
#
|
||||||
def tsort_each # :yields: node
|
def tsort_each(&block) # :yields: node
|
||||||
each_strongly_connected_component {|component|
|
each_node = method(:tsort_each_node)
|
||||||
|
each_child = method(:tsort_each_child)
|
||||||
|
TSort.tsort_each(each_node, each_child, &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
# The iterator version of the TSort.tsort method.
|
||||||
|
#
|
||||||
|
# The graph is represented by _each_node_ and _each_child_.
|
||||||
|
# _each_node_ should have +call+ method which yields for each node in the graph.
|
||||||
|
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
|
||||||
|
#
|
||||||
|
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
|
||||||
|
# each_node = lambda {|&b| g.each_key(&b) }
|
||||||
|
# each_child = lambda {|n, &b| g[n].each(&b) }
|
||||||
|
# TSort.tsort_each(each_node, each_child) {|n| p n }
|
||||||
|
# #=> 4
|
||||||
|
# # 2
|
||||||
|
# # 3
|
||||||
|
# # 1
|
||||||
|
#
|
||||||
|
def TSort.tsort_each(each_node, each_child) # :yields: node
|
||||||
|
TSort.each_strongly_connected_component(each_node, each_child) {|component|
|
||||||
if component.size == 1
|
if component.size == 1
|
||||||
yield component.first
|
yield component.first
|
||||||
else
|
else
|
||||||
|
@ -203,8 +250,34 @@ module TSort
|
||||||
# p graph.strongly_connected_components #=> [[4], [2, 3], [1]]
|
# p graph.strongly_connected_components #=> [[4], [2, 3], [1]]
|
||||||
#
|
#
|
||||||
def strongly_connected_components
|
def strongly_connected_components
|
||||||
|
each_node = method(:tsort_each_node)
|
||||||
|
each_child = method(:tsort_each_child)
|
||||||
|
TSort.strongly_connected_components(each_node, each_child)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns strongly connected components as an array of arrays of nodes.
|
||||||
|
# The array is sorted from children to parents.
|
||||||
|
# Each elements of the array represents a strongly connected component.
|
||||||
|
#
|
||||||
|
# The graph is represented by _each_node_ and _each_child_.
|
||||||
|
# _each_node_ should have +call+ method which yields for each node in the graph.
|
||||||
|
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
|
||||||
|
#
|
||||||
|
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
|
||||||
|
# each_node = lambda {|&b| g.each_key(&b) }
|
||||||
|
# each_child = lambda {|n, &b| g[n].each(&b) }
|
||||||
|
# p TSort.strongly_connected_components(each_node, each_child)
|
||||||
|
# #=> [[4], [2], [3], [1]]
|
||||||
|
#
|
||||||
|
# g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
|
||||||
|
# each_node = lambda {|&b| g.each_key(&b) }
|
||||||
|
# each_child = lambda {|n, &b| g[n].each(&b) }
|
||||||
|
# p TSort.strongly_connected_components(each_node, each_child)
|
||||||
|
# #=> [[4], [2, 3], [1]]
|
||||||
|
#
|
||||||
|
def TSort.strongly_connected_components(each_node, each_child)
|
||||||
result = []
|
result = []
|
||||||
each_strongly_connected_component {|component| result << component}
|
TSort.each_strongly_connected_component(each_node, each_child) {|component| result << component}
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -237,12 +310,41 @@ module TSort
|
||||||
# # [2, 3]
|
# # [2, 3]
|
||||||
# # [1]
|
# # [1]
|
||||||
#
|
#
|
||||||
def each_strongly_connected_component # :yields: nodes
|
def each_strongly_connected_component(&block) # :yields: nodes
|
||||||
|
each_node = method(:tsort_each_node)
|
||||||
|
each_child = method(:tsort_each_child)
|
||||||
|
TSort.each_strongly_connected_component(each_node, each_child, &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
# The iterator version of the TSort.strongly_connected_components method.
|
||||||
|
#
|
||||||
|
# The graph is represented by _each_node_ and _each_child_.
|
||||||
|
# _each_node_ should have +call+ method which yields for each node in the graph.
|
||||||
|
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
|
||||||
|
#
|
||||||
|
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
|
||||||
|
# each_node = lambda {|&b| g.each_key(&b) }
|
||||||
|
# each_child = lambda {|n, &b| g[n].each(&b) }
|
||||||
|
# TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
|
||||||
|
# #=> [4]
|
||||||
|
# # [2]
|
||||||
|
# # [3]
|
||||||
|
# # [1]
|
||||||
|
#
|
||||||
|
# g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
|
||||||
|
# each_node = lambda {|&b| g.each_key(&b) }
|
||||||
|
# each_child = lambda {|n, &b| g[n].each(&b) }
|
||||||
|
# TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
|
||||||
|
# #=> [4]
|
||||||
|
# # [2, 3]
|
||||||
|
# # [1]
|
||||||
|
#
|
||||||
|
def TSort.each_strongly_connected_component(each_node, each_child) # :yields: nodes
|
||||||
id_map = {}
|
id_map = {}
|
||||||
stack = []
|
stack = []
|
||||||
tsort_each_node {|node|
|
each_node.call {|node|
|
||||||
unless id_map.include? node
|
unless id_map.include? node
|
||||||
each_strongly_connected_component_from(node, id_map, stack) {|c|
|
TSort.each_strongly_connected_component_from(node, each_child, id_map, stack) {|c|
|
||||||
yield c
|
yield c
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -285,7 +387,7 @@ module TSort
|
||||||
#
|
#
|
||||||
# _node_ is the first node.
|
# _node_ is the first node.
|
||||||
# _each_child_ should have +call+ method which takes a node argument
|
# _each_child_ should have +call+ method which takes a node argument
|
||||||
# and yields for each adjacent node.
|
# and yields for each child node.
|
||||||
#
|
#
|
||||||
# Return value is unspecified.
|
# Return value is unspecified.
|
||||||
#
|
#
|
||||||
|
|
|
@ -41,7 +41,53 @@ class TSortTest < Test::Unit::TestCase # :nodoc:
|
||||||
a.strongly_connected_components.map {|nodes| nodes.sort})
|
a.strongly_connected_components.map {|nodes| nodes.sort})
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_noclass
|
def test_s_tsort
|
||||||
|
g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
|
||||||
|
each_node = lambda {|&b| g.each_key(&b) }
|
||||||
|
each_child = lambda {|n, &b| g[n].each(&b) }
|
||||||
|
assert_equal([4, 2, 3, 1], TSort.tsort(each_node, each_child))
|
||||||
|
g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
|
||||||
|
assert_raise(TSort::Cyclic) { TSort.tsort(each_node, each_child) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_s_tsort_each
|
||||||
|
g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
|
||||||
|
each_node = lambda {|&b| g.each_key(&b) }
|
||||||
|
each_child = lambda {|n, &b| g[n].each(&b) }
|
||||||
|
r = []
|
||||||
|
TSort.tsort_each(each_node, each_child) {|n| r << n }
|
||||||
|
assert_equal([4, 2, 3, 1], r)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_s_strongly_connected_components
|
||||||
|
g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
|
||||||
|
each_node = lambda {|&b| g.each_key(&b) }
|
||||||
|
each_child = lambda {|n, &b| g[n].each(&b) }
|
||||||
|
assert_equal([[4], [2], [3], [1]],
|
||||||
|
TSort.strongly_connected_components(each_node, each_child))
|
||||||
|
g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
|
||||||
|
assert_equal([[4], [2, 3], [1]],
|
||||||
|
TSort.strongly_connected_components(each_node, each_child))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_s_each_strongly_connected_component
|
||||||
|
g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
|
||||||
|
each_node = lambda {|&b| g.each_key(&b) }
|
||||||
|
each_child = lambda {|n, &b| g[n].each(&b) }
|
||||||
|
r = []
|
||||||
|
TSort.each_strongly_connected_component(each_node, each_child) {|scc|
|
||||||
|
r << scc
|
||||||
|
}
|
||||||
|
assert_equal([[4], [2], [3], [1]], r)
|
||||||
|
g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
|
||||||
|
r = []
|
||||||
|
TSort.each_strongly_connected_component(each_node, each_child) {|scc|
|
||||||
|
r << scc
|
||||||
|
}
|
||||||
|
assert_equal([[4], [2, 3], [1]], r)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_s_each_strongly_connected_component_from
|
||||||
g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
|
g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
|
||||||
each_child = lambda {|n, &b| g[n].each(&b) }
|
each_child = lambda {|n, &b| g[n].each(&b) }
|
||||||
r = []
|
r = []
|
||||||
|
|
Loading…
Reference in a new issue