![](/img/trans.png)
[英]How to build a Weighted Graph with Ruby's RGL or GRATR to perform Dijkstra's algorithm?
[英]How to find the shortest path from a vertex to other in a graph with a Dijkstra's algorithm
我正在开发一个TOP的项目,我应该做一个返回图形的两个顶点之间的最短路径的函数,但是我得到一个错误。 我该怎么做才能解决这个问题?
还没有,因为我是一个新手。
Graph类
class Vertex
attr_accessor :value, :neighbors, :prev, :dist
def initialize(value)
@value = value
@neighbors = []
@prev = nil
@dist = Float::INFINITY
end
def add_edge(adjacent_vertex)
@neighbors << adjacent_vertex
end
end
class Graph
attr_reader :vertices
def initialize
@vertices = {}
@dijkstra_source = nil
end
def add_vertex(vertex)
@vertices[vertex.value] = vertex
end
def add_edge(vertex1, vertex2)
@vertices[vertex1.value].add_edge(@vertices[vertex2])
@vertices[vertex2.value].add_edge(@vertices[vertex1])
end
def dijkstra(source)
return if @dijkstra_source == source
unvisited = @vertices.values
unvisited.each do |vertex|
vertex.dist = Float::INFINITY
vertex.prev = nil
end
@vertices[source].dist = 0
until unvisited.empty?
current_node = unvisited.min_by(&:dist)
break if current_node.dist == Float::INFINITY
unvisited.delete(current_node)
current_node.neighbors.each do |v|
neighbor = @vertices[v]
if unvisited.include?(neighbor)
alt = current_node.dist + 1
if alt < neighbor.dist
neighbor.dist = alt
neighbor.prev = current_node
end
end
end
end
@dijkstra_source = source
end
def find_shortest_path(source, target)
dijkstra(source)
path = []
u = target
while u
path.unshift(u)
u = @vertices[u].prev
end
return path
end
end
我在哪里设置顶点
require_relative 'graph'
class Knight
attr_reader :character, :graph
def initialize
@character = "♞"
@possible_moves = nil
@positions = Array.new(8) { Array.new(8, " ") }
@move_set = [
[-1,-2],
[-2,-1],
[-2,+1],
[-1,+2],
[+1,+2],
[+2,+1],
[+2,-1],
[+1,-2]
]
@graph = generate_graph
generate_edges
end
def generate_graph
graph = Graph.new
@positions.each_index do |x|
@positions[x].each_index do |y|
vertex = Vertex.new([x,y])
graph.add_vertex(vertex)
end
end
graph
end
def generate_edges
@graph.vertices.each do |key, value|
@move_set.each do |move|
x = key[0] + move[0]
y = key[1] + move[1]
if (0..7).include?(x) && (0..7).include?(y)
vertex = [x,y]
value.add_edge(vertex) unless value.neighbors.include?(vertex)
end
end
end
end
end
knight = Knight.new
knight.generate_edges
p knight.graph.find_shortest_path([1,2],[2,3])
我期望一个数组存储在从源顶点([1,2])到目标顶点(2,3)的最短路径内。
但不是我得到的是NilClass错误
Traceback (most recent call last):
1: from knight.rb:50:in `<main>'
/home/brito/the_odin_project/knight_moves/graph.rb:63:in `find_shortest_path': undefined method `prev' for nil:NilClass (NoMethodError)
问题是在尝试调用prev
方法时,没有初始化( nil
),如错误消息中所示。
最近的可疑调用位于Graph#find_shortest_path
。 如果您从那里打印@vertices
和 u
,您将看到在第二次迭代时, u
成为Vertex
实例 ,而@vertices
将原始值作为键。 解决方法是将u = @vertices[u].prev
为u = @vertices[u].prev.value
以保持u
为原始值 (请注意第一个检查@vertices[u].prev
地点。
总结:
def find_shortest_path(source, target)
dijkstra(source)
path = []
u = target
while u
path.unshift(u)
u = (@vertices[u].prev.value if @vertices[u].prev)
end
return path
end
此外,上面的代码将解决问题,代码不是ruby惯用; FWIW,我发布了惯用版。
我明白,这对你来说太多了不寻常的模式,但万一你有兴趣深入研究:
def find_shortest_path(source, target)
dijkstra(source)
loop.reduce([[], target]) do |(path, u), _|
break path unless u
[
path << u,
(@vertices[u].prev.value if @vertices[u].prev)
]
end
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.