我用Dijkstra算法,写了一个无环有向图/无向图(多加一条相反的路径仅此而已) 的最短路径问题的解决方案。如果是无向图也很简单,把每个无向的edge拆开成两个有向的就可以解决了。
为了每次弹出正确的端点,我也实现了一个最小优先队列。
代码由4个类构成:
Edge定义两个端点之间路径,有三个属性:源,目的地和权重。
Graph定义了整个图形,包括路径和端点。在这个code里面,端点不能单独添加。当添加路径的时候,端点会自动添加。
MinPQ定义一个优先队列,它用来储存端点到起始点的最小距离。它有一个方法del_min,用来弹出队列中距离最小的那个端点。
ShortestPath是主要类,它使用Dijkstra算法,有两个方法:
path_to(vertex)方法返回包含从起点到顶点的最短路径的list 。
main(list_Grph,from_point,to_point) //该方法主要构造 并且输出最短路径经过的节点
list_Grph 使所有边的一个list 下面有例子可以看看
from_point //从哪一个节点出发
to_point //到哪个节点
dist_to(vertex)返回path_to(vertex)的总长度。
class Edge:
def __init__(self, source, destine, weight):
self.weight = weight
self.source = source
self.destine = destine
class Graph:
def __init__(self):
self.vertices = set([])
self.edges = set([])
self.adjacents = {}
def add_edge(self, edge):
self.vertices.add(edge.source)
self.vertices.add(edge.destine)
if edge.source not in self.adjacents.keys():
self.adjacents[edge.source] = set([])
self.adjacents[edge.source].add(edge)
self.edges.add(edge)
# print("add edge from {} to {}, weight {}".format(edge.source, edge.destine, edge.weight))
def get_adjacents(self, vertex):
# print("get the adjacent vertices of vertex {}".format(vertex))
if vertex not in self.adjacents.keys():
return set([])
return self.adjacents[vertex]
def vertex_number(self):
return len(self.vertices)
def edge_number(self):
return len(self.edges)
class MinPQ:
def __init__(self):
self.queue = [(0, 0)]
# print("create a min Priority Queue to record the distance")
def is_empty(self):
return len(self.queue) == 1
def size(self):
return len(self.queue) - 1
def min(self):
return self.queue[1]
def insert(self, vertex, new_value):
self.queue.append((vertex, new_value))
self.swim(self.size())
def del_min(self):
self.queue[1], self.queue[-1] = self.queue[-1], self.queue[1]
temp = self.queue.pop(-1)
self.sink(1)
return temp
def swim(self, index):
while index > 1 and self.queue[index // 2][1] > self.queue[index][1]:
self.queue[index //
2], self.queue[index] = self.queue[index], self.queue[
index // 2]
index = index // 2
def sink(self, index):
while 2 * index <= self.size():
next_level = 2 * index
if next_level < self.size() and self.queue[next_level][
1] > self.queue[next_level + 1][1]:
next_level += 1
if self.queue[index][1] <= self.queue[next_level][1]:
return
self.queue[index], self.queue[next_level] = self.queue[
next_level], self.queue[index]
index = next_level
def contains(self, vertex):
for index in range(1, len(self.queue)):
if self.queue[index][0] == vertex:
return True
return False
def change_dist(self, vertex, new_dist):
for index in range(1, len(self.queue)):
if self.queue[index][0] == vertex:
self.queue[index] = (vertex, new_dist)
class ShortestPath:
def __init__(self, graph, start_point):
self.dist_to = {}
self.edge_to = {}
for vertex in graph.vertices:
self.dist_to[vertex] = float("inf")
self.dist_to[start_point] = start_point
self.start_point = start_point
self.dist_queue = MinPQ()
self.dist_queue.insert(start_point, self.dist_to[start_point])
# print("insert the start point into the priority queue and initialize the distance")
while not self.dist_queue.is_empty():
vertex, _ = self.dist_queue.del_min()
# print("grow the mini-distance tree by poping vertex {} from the queue".format(vertex))
for edge in graph.get_adjacents(vertex):
self.relax(edge)
def relax(self, edge):
# print("relax edge from {} to {}".format(edge.source, edge.destine))
source = edge.source
destine = edge.destine
if self.dist_to[destine] > self.dist_to[source] + edge.weight:
self.dist_to[destine] = self.dist_to[source] + edge.weight
self.edge_to[destine] = edge
if self.dist_queue.contains(destine):
self.dist_queue.change_dist(destine, self.dist_to[destine])
else:
self.dist_queue.insert(destine, self.dist_to[destine])
def dist_to(self, vertex):
return self.dist_to[vertex]
def path_to(self, vertex):
lPath = [vertex]
temp_vertex = vertex
while temp_vertex != self.start_point:
temp_vertex = self.edge_to[temp_vertex].source
lPath.append(temp_vertex)
lPath.reverse()
return lPath
def main(list_Grph,from_point,to_point):
test = Graph()
#Create an graph
for item in list_Grph:
test.add_edge(Edge(item[0], item[1],item[2]))
# you will need to the next line of code if the graph is a disorderly
#test.add_edge(Edge(item[1], item[0],item[2]))
path = ShortestPath(test, from_point)
distPath = path.path_to(to_point);
print "the distPth is :"
print distPath
def test():
edge_1=[1,2,1]
edge_2=[2,5,1]
edge_3=[2,4,1]
edge_4=[2,3,2]
edge_5=[3,4,1]
edge_6=[3,6,2]
edge_7=[4,6,1]
list_edge =[edge_1,edge_2,edge_3,edge_4,edge_5,edge_6,edge_7]
main(list_edge,5,6)
test()