单源最短路径 -- Dijkstra算法

算法描述

给出一个起始点,求出到达其他所有点的最短路径。以下图为例:假设v​1​​为源点,找从v​1​​到其它节点的最短路径。
在这里插入图片描述
结果:
v1到各节点的路径及其最短距离
v2:v1——v6——v2 = 5
v3:v1——v6——v2——v3 = 12
v4:v1——v6——v4 = 9
v5:v1——v6——v5 = 4
v6:v1——v6 = 3

在这里插入图片描述

算法实现

class Dijkstra:
    """
    单源最短路径,边权重非负
    """
    def dijkstra1(self, src: Node):
        """
        :param src:
        :return: 从src出发 到所有点的最短距离
        """
        # key:从src出发到达的节点;value:从src出发到达的节点的最短距离,
        # 若没有节点的记录,认为是正无穷
        distanceMap = dict()
        distanceMap[src] = 0
        selectedNodes = set()
        minNode = self.getMinDistanceAndUnselectedNode(distanceMap, selectedNodes)
        while minNode:
            distance = distanceMap.get(minNode)
            for edge in minNode.edges:
                dstNode = edge.dst
                if dstNode not in distanceMap.keys():
                    distanceMap[dstNode] = distance + edge.weight
                else:
                    distanceMap[edge.dst] = min(distanceMap.get(dstNode), distance + edge.weight)

            selectedNodes.add(minNode)
            minNode = self.getMinDistanceAndUnselectedNode(distanceMap, selectedNodes)

        return distanceMap

    def getMinDistanceAndUnselectedNode(self, distanceMap, touchNodes):
        minNode = None
        minDistance = float('inf')
        for node, distance in distanceMap.items():
            if node not in touchNodes and distance < minDistance:
                minNode = node
                minDistance = distance
        return minNode

改进算法【小根堆】

class Dijkstra:
    """
    单源最短路径,边权重非负
    """
    class NodeRecord:
        def __init__(self, node: Node, distance: int):
            self.node = node
            self.distance = distance

    class NodeHeap:
        def __init__(self, size: int):
            # 实际的堆结构
            self.nodes = [] * size
            # key 某一个node, value 上面堆中的位置
            self.heapIndexMap = dict()
            # key 某一个节点, value 从源节点出发到该节点的目前最小距离
            self.distanceMap = dict()
            # 堆上有多少个点
            self.size = 0

        def isEmpty(self):
            return self.size == 0

        def addOrUpdateOrIgnore(self, node: Node, distance: int):
            """
            有一个点叫node,现在发现了一个从源节点出发到达node的距离为distance
            判断要不要更新,如果需要的话,就更新
            :param node:
            :param distance:
            :return:
            """
            if self.inHeap(node):
                self.distanceMap[node] = min(self.distanceMap.get(node), distance)
                self.insertHeapify(node, self.heapIndexMap.get(node))
            if not self.isEntered(node):
                self.nodes[self.size] = node
                self.heapIndexMap[node] = self.size
                self.distanceMap[node] = distance
                self.insertHeapify(node, self.size)
                self.size += 1

        def isEntered(self, node: Node):
            return self.heapIndexMap.__contains__(node)

        def inHeap(self, node: Node):
            return self.isEntered(node) and self.heapIndexMap.get(node) != -1

        def insertHeapify(self, node: Node, index: int):
            while self.distanceMap.get(self.nodes[index]) < self.distanceMap.get(self.nodes[(index-1)//2]):
                self.swap(index, (index-1)//2)
                index = (index-1)//2

        def heapify(self, index: int, size: int):
            left = index * 2 + 1
            while left < size:
                if left + 1 < size and self.distanceMap.get(self.nodes[left+1]) < self.distanceMap.get(self.nodes[left]):
                    smallest = left+1
                else:
                    smallest = left

                smallest = smallest if self.distanceMap.get(self.nodes[smallest]) < self.distanceMap.get(self.nodes[index]) else index

                self.swap(smallest, index)
                index = smallest
                left = index * 2 + 1

        def swap(self, index1: int, index2: int):
            self.heapIndexMap[self.nodes[index1]] = index2
            self.heapIndexMap[self.nodes[index2]] = index1
            self.nodes[index1], self.nodes[index2] = self.nodes[index2],  self.nodes[index1]

        def pop(self):
            nodeRecord = Dijkstra.NodeRecord(self.nodes[0], self.distanceMap.get(self.nodes[0]))
            self.swap(0, self.size - 1)
            self.heapIndexMap[self.nodes[self.size-1]] = -1
            self.distanceMap.pop(self.nodes[self.size-1])
            self.nodes[self.size-1] = None
            self.heapify(0, self.size-1)
            self.size -= 1
            return nodeRecord

    def dijkstra2(self, src: Node):
        """
        改写堆
        :param src:
        :return:
        """
        nodeHeap = Dijkstra.NodeHeap()
        nodeHeap.addOrUpdateOrIgnore(src, 0)
        result = dict()
        while nodeHeap:
            record = nodeHeap.pop()
            cur = record.node
            distance = record.distance
            for edge in cur.edges:
                nodeHeap.addOrUpdateOrIgnore(edge.dst, edge.weight+distance)
            result[cur] = distance

        return result
### 回答1: Dijkstra算法是一种用于解决单源最短路径问题的算法。它的基本思想是从起点开始,逐步扩展到其他节点,每次选择当前距离起点最近的节点,并更新与该节点相邻的节点的距离。通过这种方式,可以找到起点到其他节点的最短路径。Dijkstra算法的时间复杂度为O(n^2),但是可以通过使用堆优化来将其优化到O(nlogn)。 ### 回答2: Dijkstra算法是一种解决单源最短路径问题的贪心算法,其思想是利用“松弛”操作来不断更新当前点到源点的最短距离,但前提是所有边的权重非负。如果有负权边,则需要使用Bellman-Ford算法。 首先,我们需要定义一个数组dis数组,用于存储源点s到各个点的最短距离。dis[s]初始为0,其他点初始为无限大。接着,我们需要维护一个集合S,表示已经求出最短路径的点的集合。将源点s加入集合S中。 对于每个未加入S的点v,我们通过选择其它点到源点s的最短路径中的一个点u,然后将dis[v]更新为dis[u] + w(u,v),其中w(u,v)表示边(u,v)的权重。具体地,这个操作称为“松弛”操作。 在松弛操作中,我们需要比较dis[u] + w(u,v)和dis[v]的大小,如果前者更小,则更新dis[v]的值为dis[u] + w(u,v)。 重复执行以上操作,直到所有的点都加入到集合S中。最后dis数组中存储的就是源点s到所有点的最短距离。 Dijkstra算法可以用堆优化,时间复杂度为O(mlogn),其中n表示图中的点数,m表示边数。Dijkstra算法也可以应用于稠密图,时间复杂度为O(n^2)。 总之,Dijkstra算法是一种经典的求解单源最短路径问题的算法,其实现简单,效率高,被广泛应用于路由算法和图像处理等领域。 ### 回答3: Dijkstra算法是一种在加权有向图中寻找从源节点到其他节点的最短路径的贪心算法。该算法基于其它路径加权节点的已知最短路径去更新更长路径的信息直到找到从源节点到目标节点的最短路径。在整个计算过程中,Dijkstra算法需要维护一个待处理节点集合和一个距离源节点的最短路径数组。 算法的具体实现如下: 1. 初始化源节点及其距离为0,其他节点的距离为无穷大。 2. 将源节点加入到待处理节点集合中。 3. 对于源节点的所有相邻节点,更新它们距离源节点的最短路径。如果当前路径小于之前已知的最短路径,则更新最短路径数组。 4. 遍历待处理节点集合中除源节点外的节点,选择距离最近的节点作为当前节点,并将它从待处理机集合中移除。 5. 对于当前节点的所有相邻节点,更新它们距离源节点的最短路径。如果当前路径小于之前已知的最短路径,则更新最短路径数组。 6. 重复步骤4和5,直到待处理节点集合为空或者目标节点已经被遍历。 Dijkstra算法的时间复杂度为O(n^2),其中n为节点数,由于它是贪心算法,只能处理非负权重的图,否则可能会陷入死循环。但是,Dijkstra算法单源最短路径问题的最优解,因此在处理小规模的图时效果很好。在处理大规模图时,需要使用其他高效的算法,如A*算法、Bellman-Ford算法等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NLP_wendi

谢谢您的支持。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值