当前位置 博文首页 > 看写写:Dijkstra算法python的实现(有向图/无向图)

    看写写:Dijkstra算法python的实现(有向图/无向图)

    作者:[db:作者] 时间:2021-09-07 13:23

    我用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()
    cs