lib/rgl/connected_components.rb in rgl-0.4.0 vs lib/rgl/connected_components.rb in rgl-0.5.0

- old
+ new

@@ -9,106 +9,112 @@ module RGL module Graph # Compute the connected components of an undirected graph, using a - # DFS (Depth-first search)-based approach. A _connected component_ of + # DFS (Depth-first search)-based approach. A _connected component_ of # an undirected graph is a set of vertices that are all reachable # from each other. # # The function is implemented as an iterator which calls the client # with an array of vertices for each component. # # It raises an exception if the graph is directed. - + # def each_connected_component raise NotUndirectedError, - "each_connected_component only works " + - "for undirected graphs." if directed? + "each_connected_component only works " + + "for undirected graphs." if directed? + comp = [] vis = DFSVisitor.new(self) vis.set_finish_vertex_event_handler { |v| comp << v } - vis.set_start_vertex_event_handler { |v| + + vis.set_start_vertex_event_handler do |v| yield comp unless comp.empty? comp = [] - } + end + depth_first_search(vis) { |v| } yield comp unless comp.empty? end # This GraphVisitor is used by strongly_connected_components to compute # the strongly connected components of a directed graph. - + # class TarjanSccVisitor < DFSVisitor attr_reader :comp_map # Creates a new TarjanSccVisitor for graph _g_, which should be directed. - - def initialize (g) + # + def initialize(g) super g @root_map = {} @comp_map = {} @discover_time_map = {} @dfs_time = 0 @c_index = 0 @stack = [] end - def handle_examine_vertex (v) - @root_map[v] = v - @comp_map[v] = -1 - @dfs_time += 1 + def handle_examine_vertex(v) + @root_map[v] = v + @comp_map[v] = -1 + @dfs_time += 1 @discover_time_map[v] = @dfs_time @stack.push(v) end - def handle_finish_vertex (v) + def handle_finish_vertex(v) # Search adjacent vertex w with earliest discover time root_v = @root_map[v] + graph.each_adjacent(v) do |w| if @comp_map[w] == -1 root_v = min_discover_time(root_v, @root_map[w]) end end + @root_map[v] = root_v - if root_v == v # v is topmost vertex of a SCC - begin # pop off all vertices until v + + if root_v == v # v is topmost vertex of a SCC + begin # pop off all vertices until v w = @stack.pop @comp_map[w] = @c_index end until w == v @c_index += 1 end end # Return the number of components found so far. - + # def num_comp @c_index end private - def min_discover_time (u, v) + def min_discover_time(u, v) @discover_time_map[u] < @discover_time_map[v] ? u : v end - end # class TarjanSccVisitor + end # class TarjanSccVisitor # This is Tarjan's algorithm for strongly connected components, from his - # paper "Depth first search and linear graph algorithms". It calculates - # the components in a single application of DFS. We implement the + # paper "Depth first search and linear graph algorithms". It calculates + # the components in a single application of DFS. We implement the # algorithm with the help of the DFSVisitor TarjanSccVisitor. # # === Definition - # + # # A _strongly connected component_ of a directed graph G=(V,E) is a # maximal set of vertices U which is in V, such that for every pair of - # vertices u and v in U, we have both a path from u to v and a path + # vertices u and v in U, we have both a path from u to v and a path # from v to u. That is to say, u and v are reachable from each other. - # - # @Article{Tarjan:1972:DFS, + # + # @Article!{Tarjan:1972:DFS, # author = "R. E. Tarjan", # key = "Tarjan", # title = "Depth First Search and Linear Graph Algorithms", # journal = "SIAM Journal on Computing", # volume = "1", @@ -119,20 +125,22 @@ # CODEN = "SMJCAT", # ISSN = "0097-5397 (print), 1095-7111 (electronic)", # bibdate = "Thu Jan 23 09:56:44 1997", # bibsource = "Parallel/Multi.bib, Misc/Reverse.eng.bib", # } - # + # # The output of the algorithm is recorded in a TarjanSccVisitor _vis_. # vis.comp_map will contain numbers giving the component ID assigned to # each vertex. The number of components is vis.num_comp. - + # def strongly_connected_components raise NotDirectedError, - "strong_components only works for directed graphs." unless directed? + "strong_components only works for directed graphs." unless directed? + vis = TarjanSccVisitor.new(self) depth_first_search(vis) { |v| } vis end - end # module Graph -end # module RGL + end # module Graph + +end # module RGL