在执行 DFS算法以查找最大的组件时,我遇到stack level too deep
的问题。事实是,我正在将map(.osm)文件转换为图形。我想找到最大的组件。但是,使用较小的地图(缩放较大)可以工作,但是使用较大的图形可以使我得到高于状态的误差,您能帮我吗?
这是导致问题的DFS代码:
def dfsFunction (vertex)
@dfs[vertex] = true
@component[@componentIndex] << vertex
adjectenVertices = []
@edges.each do |edge|
if edge.v1.id == vertex.id
adjectenVertices << edge.v2
elsif edge.v2.id == vertex.id
adjectenVertices << edge.v1
end
end
adjectenVertices.each_with_index do |vertex|
if @dfs[vertex] == false
dfsFunction(vertex)
end
end
end
@dfs = {}
@vertices.each do |id,vertex|
@dfs[vertex] = false
end
@component = {}
@componentIndex = -1
@dfs.each do |vertex, boolean|
if @dfs[vertex] == false
@componentIndex = @componentIndex +1
@component[@componentIndex] = []
dfsFunction(vertex)
end
end
答案 0 :(得分:0)
这里的问题是,您使用了递归,对于复杂的图形它越来越深了。对于每次递归,必须增加堆栈以保存结果值。 要解决此问题,您可以做两件事:更改为循环或重写经过尾调用优化的递归,并为ruby启用尾调用优化(有关一些解释,请参见http://nithinbekal.com/posts/ruby-tco/)。
我制作了一个小版本,使用while循环。希望对您有帮助...
class Edge
attr_reader :left, :right
def initialize(left, right)
@left, @right = left, right
end
def vertexes
[left, right]
end
end
class Graph
attr_reader :vertexes, :edges
def initialize(vertexes, edges)
@vertexes, @edges = vertexes, edges
end
def add_edges(new_edges)
new_edges.each { |edge| add_edge(edge) }
end
def add_edge(edge)
add_vertex(edge.left)
add_vertex(edge.right)
@edges << edge
@edges.uniq!
edge
end
def add_vertex(vertex)
@vertexes << vertex
@vertexes.uniq!
vertex
end
def edges_for(vertex)
edges.select { |edge| edge.left == vertex || edge.right == vertex }
end
end
module DFS
def self.components(graph)
vertexes = graph.vertexes.clone
graph.vertexes.map do |vertex|
next unless vertexes.delete(vertex)
component = Graph.new([vertex], [])
edges = graph.edges_for(vertex)
while (new_vertexes = edges.map(&:vertexes).flatten & vertexes).any? do
component.add_edges(edges)
edges = new_vertexes.map { |new_vertex| graph.edges_for(new_vertex) }.flatten
vertexes -= new_vertexes
end
component.add_edges(edges)
component
end.compact
end
end
答案 1 :(得分:0)
MRI默认情况下关闭了尾递归优化。但是可能会打开它:
RubyVM::InstructionSequence.compile_option = {
tailcall_optimization: true,
trace_instruction: false
}
此外,代码本身必须使用尾部递归,例如:
def test(v)
return unless v > 0
p v
test(v-1)
end
代替:
def test(v)
test(v-1) if v > 0
p v
end