算法-数据结构入门(六)——《算法图解》

在(五)里面我们简单说了广度优先搜索算法,它可以找出到达目标节点的段数最少的路径;但是像下图这样(书上图):

从双子峰到金门大桥用时最少的路径,怎么求呢?如果 用广度优先搜索,最后得到的最短路径是3段,即最上面的那条路径,但不是用时最短的,这节我们介绍一种新的算法:狄克斯特拉算法

狄克斯特拉算法包含四个步骤:

1.先找出最便宜的节点,即在最短时间可以到达的节点

2.更新该节点邻居的开销(即有没有前往它们更短的路径,有则更新,具体表现见下面的例子)

3.重复1,2,直到图中每个节点都被遍历

4.计算最终路径

 

先介绍几个概念,像上图这样,每条边上都标有数字,这些数字称为权重,这种图称为加权图

狄克斯特拉算法适用于有向加权无环图。无向图意味着两个节点彼此互相指向,也就是环,而绕环的路径不可能是最短的路径。

我们看一个简单的例子(书上)代码实现狄克斯特拉算法:

如图,要找出从起点start到终点end的最短路径。

思考:首先我们要像上一节一样,用数据结构把这个图存起来,按上一节的经验,我们用的是散列表的键存储节点,值存储它的邻居,但是现在还有权重需要存储,那我们就可以使用双层散列表(类似于二维数组),像下图 

代码:

graph = {}
graph['start'] = {}
graph['start']['a'] = 6
graph['start']['b'] = 2
graph['a'] = {}
graph['a']['end'] = 1
graph['b'] = {}
graph['b']['a'] = 3
graph['b']['end'] = 5

根据狄克斯特拉算法第二步,我们需要用一个散列表存储除起始点外每个节点的开销(从起点出发到该节点需要多长时间),以方便更新,代码如下:

infinity = float('inf')
costs = {}
costs['a'] = 6
costs['b'] = 2
costs['end'] = infinity

因为从起始点到终点的距离未知,所以用无穷大来暂时表示:infinity = float('inf')。

然后我们在更新开销之后,节点的父节点也会相应的改变,所以还需一个散列表来存储父节点,代码如下:

parents = {}
parents['a'] = 'start'
parents['b'] = 'start'
parents['end'] = Node 

然后需要一个数组记录处理过的节点,已处理的不需要重复处理:

processsed = []

具体算法如下:

1.只要还有要处理的节点(costs中取)

2.获取离节点最近的节点

3.更新其邻居的开销

4.如果有邻居的开销被更新则同时更新它的父节点(parents)

5.将节点标记为处理过(加入processed),返回第一步

代码如下:

graph = {}
graph['start'] = {}
graph['start']['a'] = 6
graph['start']['b'] = 2
graph['a'] = {}
graph['a']['end'] = 1
graph['b'] = {}
graph['b']['a'] = 3
graph['b']['end'] = 5
graph['end'] = {}

infinity = float('inf')
costs = {}
costs['a'] = 6
costs['b'] = 2
costs['end'] = infinity

parents = {}
parents['a'] = 'start'
parents['b'] = 'start'
parents['end'] = None

processsed = []

def find_lowest_cost_node(costs):
    lowest_cost = float('inf')
    lowest_cost_node = None
    for node in costs:
        cost = costs[node]
        if cost < lowest_cost and node not in processsed:
            lowest_cost = cost
            lowest_cost_node = node
    return lowest_cost_node
    
node = find_lowest_cost_node(costs)

while node is not None:
    cost = costs[node]
    neighbors = graph[node]
    for n in neighbors.keys():
        new_cost = cost + neighbors[n]
        if new_cost < costs[n]:
            costs[n] = new_cost
            parents[n] = node
    processsed.append(node)
    node = find_lowest_cost_node(costs)
    
print costs['end']

补:如果加权图中有负权,则不可以用狄克斯特拉算法,要用贝尔曼-福德算法(暂不讨论)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值