哈希图填充如下:
{"1"=>["2"], "2"=>["3", "7"], "3"=>["4"], "5"=>["6", "2"], "6"=>["7"], "7"=>["8", "4"]}
,以便每个键可以具有多个值。这些值代表一组路线上的公交车站,例如从公交车站1可以到达2,从公交车站2可以到达3或7,依此类推。
我正在尝试遍历此图结构,并从给定的起点查找长度大于1的所有可能路径。例如,对于起点1,所有可能路径的列表将为
[[1,2] , [1,2,3] , [1,2,3,4] , [1,2,7] , [1,2,7,8], [1,2,7,4]]
我试图递归地解决此问题,在该迭代中,我遍历当前键的子级(该键的值)并调用一个实质上扩展该键的子级的函数。到目前为止,这是我的代码:
if hash.has_key?(origin.to_s)
tmp = origin.to_s
tmp << hash[origin.to_s][0]
paths.push(tmp)
expand_node(hash,paths,paths.length-1,tmp[tmp.length-1])
end
起点是起点。首先,我将第一个路径(在这种情况下为[1,2]
)添加到名为paths
的数组中,然后展开添加到前一个路径(在这种情况下为2
)中的最后一个值。
def expand_node(hash,paths,curr_paths_index,node)
curr_node = node
if hash.has_key?(node.to_s)
counter = 0
hash[curr_node].each do |child|
tmp = paths[curr_paths_index]
tmp << child
paths << tmp
curr_paths_index += counter + 1
puts paths
expand_node(hash,paths,curr_paths_index,child)
end
end
结束
自变量curr_paths_index
跟踪我扩展的路径。
参数path
是当前找到的路径的完整列表。
参数node
是要扩展的当前值。
函数完成后打印paths
会产生:
123
123
1234
1234
1234
12347
12347
12347
12347
123478
123478
123478
123478
123478
1234784
1234784
1234784
1234784
1234784
1234784
有什么方法可以修改此代码,以便产生所需的输出(如上所示)?总的来说,有没有更好的方法来解决这个问题?
谢谢。
答案 0 :(得分:2)
解决递归问题的一种方法是先将其分解为易于解决的单个案例,然后将其归纳。这是一个更简单的情况:
给出一个图和该图的路径,确定可以将哪些节点添加到该路径的末尾而无需创建循环。
如果我们能够解决这个问题,我们也可以轻松解决更大的问题。
请注意,如果在步骤2中找不到新节点,则由于第3步和第4步无关,因此递归调用将终止。
这是我解决步骤2的方法,我将递归部分留给您
def find_next_nodes graph, path
graph[path[-1]].reject { |node| path.include? node }
end
答案 1 :(得分:1)
我会这样做,很确定可以进一步优化它,并且性能可能也会出现问题。
require 'set'
dt = {"1"=>["2"], "2"=>["3", "7"], "3"=>["4"], "5"=>["6", "2"], "6"=>["7"], "7"=>["8", "4"]}
def traverse(initial_hash, key_arrays, traversed_keys = [])
value = []
key_arrays.map do |key|
n = [*traversed_keys, key]
value << n unless n.count == 1 # prevent first key to be added
another_keys = initial_hash.fetch(key, nil) # try to load the value, fallback to nil if key not found
if another_keys.nil? # stop condition
value << n
elsif another_keys.is_a?(Enumerable) # if key found
another_keys.map do |ank| # recursive
value.concat([*traverse(initial_hash, [ank], n)]) # splat operator to unpack the array
end
end
end
value.to_set # only return unique value, can be converted to array if needed
end
traverse(dt, [1].map(&:to_s)).map { |val| val.join('') }
对不起,但是我还没有调试您的代码,所以我认为temp变量存在问题,因为无法扩展的路径将继续到下一次迭代。
答案 2 :(得分:1)
def doit(graph, start)
return [] unless graph.key?(start)
recurse(graph, start).drop(1)
end
def recurse(graph, start)
(graph[start] || []).each_with_object([[start]]) { |next_node, arr|
recurse(graph, next_node).each { |a| arr << [start, *a] } }
end
graph = { 1=>[2], 2=>[3, 7], 3=>[4], 5=>[6, 2], 6=>[7], 7=>[8, 4] }
doit(graph, 1)
#=> [[1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 7], [1, 2, 7, 8],
# [1, 2, 7, 4]]
doit(graph, 2)
#=> [[2, 3], [2, 3, 4], [2, 7], [2, 7, 8], [2, 7, 4]]
doit(graph, 3)
#=> [[3, 4]]
doit(graph, 5)
#=> [[5, 6], [5, 6, 7], [5, 6, 7, 8], [5, 6, 7, 4], [5, 2],
# [5, 2, 3], [5, 2, 3, 4], [5, 2, 7], [5, 2, 7, 8], [5, 2, 7, 4]]
doit(graph, 6)
#=> [[6, 7], [6, 7, 8], [6, 7, 4]]
doit(graph, 7)
#=> [[7, 8], [7, 4]]
doit(graph, 4)
#=> []
doit(graph, 99)
#=> []