spfa算法的python实现

SPFA算法是对Bellman-Ford算法的改进,使用了队列进行了优化,在时间复杂度上,一般情况下是优于Dijkstra算法的。在SPFA算法中每次仅对最短路径估计值发生改变了的顶点的所有出边执行松弛操作。并使用队列来维护这些发生了变化的点。每次选取队首顶点u的所有边进行松弛操作,假设有一条u到v的边,如果通过这条边使得源点到顶点v的最短路程变短,且顶点v不在当前队列中,就将顶点v放入队尾。

算法过程

queue<int> q;
源点s入队;
while(队列非空){
    取出队首元素;
    for(u的所有邻接边u->v){
        if(d[u]+dis<d[v])
        {
            d[v]=d[u]+dis;
            if(v当前不在队列)
            {
                v入队;
                if(v入队次数大于n-1){
                    说明有可达负环,return;
                }
            }
        }
    }
}

算法实现

adjacencyList.py
class Vertex:
    def __init__(self,key):
        self.id = key
        self.connectedTo = {}

    # 从这个顶点添加一个连接到另一个
    def add_neighbor(self, nbr, weight=0):
        self.connectedTo[nbr] = weight

    def __str__(self):
        return str(self.id) + ' connectedTo ' + str([x for x in self.connectedTo])

    # 返回邻接表中的所有的项点
    def get_connections(self):
        return self.connectedTo.keys()

    def get_id(self):
        return self.id

    # 返回从这个顶点到作为参数顶点的边的权重
    def get_weight(self, nbr):
        return self.connectedTo[nbr]


class Graph:
    def __init__(self, num=None):
        self.vertList = {}
        self.numVertices = 0
        if num is not None:
            [self.add_vertex(i+1) for i in range(num)]

    def add_vertex(self, key):
        self.numVertices += 1
        v = Vertex(key)
        self.vertList[key] = v
        return v

    def get_vertex(self, n):
        if n in self.vertList:
            return self.vertList[n]
        else:
            return None

    def __contains__(self, item):
        return item in self.vertList

    def add_edge(self, u, v, w = float('inf')):
        if u not in self.vertList:
            self.add_vertex(u)
        if v not in self.vertList:
            self.add_vertex(v)
        self.vertList[u].add_neighbor(self.vertList[v].get_id(), w)

    def get_vertices(self):
        return self.vertList.keys()

    def __iter__(self):
        return iter(self.vertList.values())

spfa.py

import queue
from adjacencyList import Graph


def spfa(graph, src):
    if graph is None:
        return None
    dis = [float('inf') if i != src else 0 for i in range(graph.numVertices + 1)]
    # 表示结点i是否在队列中
    book = [False for i in range(graph.numVertices + 1)]
    que = queue.Queue()
    que.put(graph.get_vertex(src))
    while not que.empty():
        u = que.get()
        u_id = u.get_id()
        con = [nei for nei in u.get_connections()]
        for c in con:
            if dis[c] > dis[u_id] + u.get_weight(c):
                dis[c] = dis[u_id] + u.get_weight(c)

                if not book[c]:
                    # 如果当前访问结点没有在队列中,就入队
                    que.put(graph.get_vertex(c))
                    book[c] = True

        # 出队
        book[u_id] = False

    return dis[1:]


if __name__ == '__main__':
    graph = Graph(5)
    graph.add_edge(1, 2, 2)
    graph.add_edge(1, 5, 10)
    graph.add_edge(2, 3, 3)
    graph.add_edge(2, 5, 7)
    graph.add_edge(3, 4, 4)
    graph.add_edge(4, 5, 5)
    graph.add_edge(5, 3, 6)

    print(spfa(graph, 1))

运行结果

参考:邻接表的python实现 - youngliu91 - 博客园

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值