基础算法-dijkstra最短路算法

最短路算法dijkstra的运用

寻找到达城市的最短路径



如图

avater


1、一般用邻接矩阵表示一个图

邻接矩阵:

A = [
	if exist(A(i,j)):
		return 1
	else:
		return 0
]

则一个图的表示方法:

INF = 999
graph = [
    [0, INF, INF, INF, INF, INF, INF, INF, INF, INF],
    [4, 0, INF, INF, INF, INF, INF, INF, INF, INF],
    [6, INF, 0, INF, INF, INF, INF, INF, INF],
    [INF, 5, INF, 0, INF, INF, INF, INF, INF],
    [INF, 7, 3, 3, 0, INF, INF, INF, INF, INF, INF],
    [INF, INF, 13, INF, INF, 0, INF, INF, INF, INF],
    [INF, INF, INF, 3, 2, INF, 0, INF, INF, INF],
    [INF, INF, INF, INF, 9, 1, INF, 0, INF, INF],
    [INF, INF, INF, INF, INF, 5, 3, 4, 0, INF]
 ]

2、为了好看我们用地图字典表示图

graph = {
        "北京": {"天津": 4, "苏州": 6, "北京": 0},
        "天津": {"上海": 5, "杭州": 7, "天津": 0},
        "苏州": {"杭州": 3, "郑州": 13, "苏州": 0},
        "上海": {"杭州": 3, "福州": 3, "上海": 0},
        "杭州": {"福州": 2, "合肥": 9, "杭州": 0},
        "郑州": {"合肥": 1, "广州": 5, "郑州": 0},
        "福州": {"广州": 3, "福州": 0},
        "合肥": {"广州": 4, "合肥": 0},
        "广州": {"广州": 0}
    }

3、dijkstra算法以及实现

(1)输入:

  • 1)图graph
  • 2)源点v0

(2)算法原理

1)一开始 S里面只有源点 v0
2)离 v0最近的那个点为 u,把 u放进 S,并且记录这一次,到达 u的点和最短路
3)查看当前能够到达的点,列出所有能够到达的点它到源点的距离,排序后,最短的那个是新的 u
4)重复1-3,直到 S包含所有 graph的点

(3)定义变量:

1)有一个集合S,存放已经走过的点
2)有一个节点u,代表下一个要放进S的点
3)有一个数据结构dist{[shortest_path],<shortest_path_value>},用来存放最短路径和最短路的值
4)有一个shortest_path{},以 <key,value> 的形式存放,最短路径中,到达节点 key的上一个节点作为 value 的值。

(4)代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-


INF = 999


class Dijkstra(object):
    """
    用dijkstra求最短路,输入参数为一个图和源点,graph实际是上一个二维数组,source表示的是二维数组中的第行个元素是源
    时间复杂度O(n^2)
    """
    def __init__(self, graph, source):
        self.graph = graph
        self.dist = {}
        self.short_path = {}
        self.s_collect = set()

        self.source = source

    def get_shortest_path_src_to_dest(self, des):
        """
        获取到达某目的地点的最短路信息
        :param dis: 目的地点
        :return:
        """
        distance = self.get_shortest_path()
        return distance[des]

    def get_shortest_path(self):
        """
        获取全图的所有最短路径信息
        :return:
        """
        self._exec_shortest_path_calculation()
        for key in self.dist.keys():
            k = key
            while k != self.source:  # 获取路径
                self.dist[key][0].insert(0, self.short_path[k])
                k = self.short_path[k]
        return self.dist

    def _exec_shortest_path_calculation(self):
        """
        计算最短路,得到图中最短路的信息
        :return:
        """
        now_node = self.source
        self.dist = dict((k, [[], INF]) for k in self.graph.keys())  # 假设初始化点到原点都是无限大
        self.dist[now_node][1] = 0  # 源点到源点的距离为0

        while len(self.s_collect) < len(self.graph):
            self.s_collect.add(now_node)

            for next in self.graph[now_node]:
                if self.dist[now_node][1] + self.graph[now_node][next] < self.dist[next][1]:
                    self.short_path[next] = now_node  # next的点来自哪个节点
                    self.dist[next][1] = self.dist[now_node][1] + self.graph[now_node][next]

            new_short = INF  # 从剩下的未确定点中选择最小距离点作为新的扩散点
            for now in self.dist.keys():
                if now in self.s_collect:
                    continue
                if self.dist[now][1] < new_short:
                    new_short = self.dist[now][1]
                    now_node = now


def print_path(source, short_path):
    for key, path in short_path.items():
        if key == source:
            continue
        path[0].append(key)
        print("%s 到 %s 最短路径为:%s, 路径: %s"
              % (source, key, path[1], "->".join(path[0])))


def main():
    source = "北京"
    graph = {
        "北京": {"天津": 4, "苏州": 6, "北京": 0},
        "天津": {"上海": 5, "杭州": 7, "天津": 0},
        "苏州": {"杭州": 3, "郑州": 13, "苏州": 0},
        "上海": {"杭州": 3, "福州": 3, "上海": 0},
        "杭州": {"福州": 2, "合肥": 9, "杭州": 0},
        "郑州": {"合肥": 1, "广州": 5, "郑州": 0},
        "福州": {"广州": 3, "福州": 0},
        "合肥": {"广州": 4, "合肥": 0},
        "广州": {"广州": 0}
    }

    dj = Dijkstra(graph, source)
    print_path(source, dj.get_shortest_path())


if __name__ == '__main__':
    main()

运行结果:
avater

4、邻接矩阵和图的字典表示法互换方法:

#!/usr/bin/env python
# -*- coding: utf-8 -*-


# adjacency martix
INF = 999
graph_mapper = {
    0: "北京",
    1: "天津",
    2: "苏州",
    3: "上海",
    4: "杭州",
    5: "郑州",
    6: "福州",
    7: "合肥",
    8: "广州"
}

graph = [
    [0, 4, 6, INF, INF, INF, INF, INF, INF, ],
    [INF, 0, INF, 5, 7, INF, INF, INF, INF, ],
    [INF, INF, 0, INF, 3, 13, INF, INF, INF, ],
    [INF, INF, INF, 0, 3, INF, 3, INF, INF, ],
    [INF, INF, INF, INF, 0, INF, 2, 9, INF, ],
    [INF, INF, INF, INF, INF, 0, INF, 1, 5, ],
    [INF, INF, INF, INF, INF, INF, 0, INF, 3, ],
    [INF, INF, INF, INF, INF, INF, INF, 0, 4, ],
    [INF, INF, INF, INF, INF, INF, INF, INF, 0, ]
]


def adjacency_to_dictmap(graph_adjacency, graph_mapper):
    """
    邻接矩阵转字典图
    :param graph_adjacency:
    :return:
    """
    graph_dict = {}
    for i in range(len(graph_adjacency)):
        graph_dict[graph_mapper[i]] = {}
        for j in range(len(graph_adjacency[i])):
            if graph_adjacency[i][j] != INF:
                graph_dict[graph_mapper[i]][graph_mapper[j]] = graph_adjacency[i][j]
    return graph_dict


def dictmap_to_adjacency(graph_dictmap, graph_mapper):
    graph_mapper_re = dict(zip(graph_mapper.values(), graph_mapper.keys()))
    print(graph_mapper_re)


def main():
    graph_dict = adjacency_to_dictmap(graph, graph_mapper)
    import pprint
    pprint.pprint(graph_dict)


if __name__ == '__main__':
    main()

运行结果:
avater

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值