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

本文介绍了一种使用Dijkstra算法解决无环有向图/无向图最短路径问题的方法,包括最小优先队列的实现以及代码结构解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我用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()
Dijkstra算法是一种用于寻找带权重无负权图中最短路径的贪心算法。在Python中,我们可以使用`heapq`模块配合邻接表数据结构来实现Dijkstra算法。以下是简单的步骤: 1. **初始化**:设置起点的距离为0,其他所有点的距离设为无穷大,将起点加入优先队列。 2. **查找最短路径**:从优先队列中取出距离最小的节点u,更新与其相邻节点v的距离,如果通过u到v的实际距离小于v当前的距离,那么更新v的距离并将v加入队列。 3. **重复直到结束**:当优先队列为空或者找到目标节点时,算法结束。如果队列中没有节点,则表示图中存在负权环,Dijkstra算法无法处理这种情况。 4. **返回结果**:最后得到的目标节点即为目标点的最短路径,通过回溯可以找出完整的路径。 在Python中,你可以按照上述逻辑编写一段代码,例如: ```python import heapq def dijkstra(graph, start): distances = {node: float('inf') for node in graph} distances[start] = 0 queue = [(0, start)] while queue: current_distance, current_node = heapq.heappop(queue) if current_distance > distances[current_node]: continue for neighbor, weight in graph[current_node].items(): distance = current_distance + weight if distance < distances[neighbor]: distances[neighbor] = distance heapq.heappush(queue, (distance, neighbor)) return distances, get_shortest_path(start, distances) # 定义图的邻接字典或其他合适的数据结构,get_shortest_path是一个辅助函数用于回溯路径 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值