[英]How to find the shortest path from a vertex to other in a graph with a Dijkstra's algorithm
I'm working on a TOP's project where i should do a function that return the shortest path between two vertices of a graph, but i get an error. 我正在开发一个TOP的项目,我应该做一个返回图形的两个顶点之间的最短路径的函数,但是我得到一个错误。 What can i do to solve this?
我该怎么做才能解决这个问题?
Nothing yet because i am a newbie. 还没有,因为我是一个新手。
the Graph class 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
Where i instatiane the vertices 我在哪里设置顶点
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])
I expect an array which stores inside the shortest path from a source vertex([1,2]) to a target vertex(2,3). 我期望一个数组存储在从源顶点([1,2])到目标顶点(2,3)的最短路径内。
But instead of that what i get is a NilClass error 但不是我得到的是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)
The issue is with something being not initialized ( nil
) while an attempt to call prev
method on it, as might be seen from the error message. 问题是在尝试调用
prev
方法时,没有初始化( nil
),如错误消息中所示。
The nearest suspicious call is in Graph#find_shortest_path
. 最近的可疑调用位于
Graph#find_shortest_path
。 If you'd print the @vertices
and u
from there, you'll see that on the second iteration u
becomes the Vertex
instance , while @vertices
has raw values as keys. 如果您从那里打印
@vertices
和 u
,您将看到在第二次迭代时, u
成为Vertex
实例 ,而@vertices
将原始值作为键。 The fix would be to change u = @vertices[u].prev
to u = @vertices[u].prev.value
to keep u
being the raw value (note the check for the @vertices[u].prev
in the first place. 解决方法是将
u = @vertices[u].prev
为u = @vertices[u].prev.value
以保持u
为原始值 (请注意第一个检查@vertices[u].prev
地点。
The summing up: 总结:
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
Also the code above would fix the issue, the code is not ruby idiomatic; 此外,上面的代码将解决问题,代码不是ruby惯用; FWIW, I'd post the idiomatic version.
FWIW,我发布了惯用版。
I understand, it's too much of uncommon patterns for you yet, but just in case you'd be interested to dig into: 我明白,这对你来说太多了不寻常的模式,但万一你有兴趣深入研究:
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.