狄克斯特拉Python实现

Dijkstra算法实现与测试用例
该博客介绍了Dijkstra算法的实现过程,包括数据结构的定义、关键操作以及算法的具体步骤。提供了多个测试用例,包括正常路径、无法到达终点的情况以及不同规模的网络。

数据结构

1、路由信息
dictRoute = {}
dictRoute[nodeId] = {}
dictRoute[nodeId][nebrId] = distance
操作:
①根据nodeId找到该node的路由信息
②根据nebrId找到某一条路由的距离

2、节点信息
dictNode = {}
dictNode[nodeId] = [shortDis, fatherId, bIsCheck]
操作:
①找到nodes中最短距离的节点
②查找节点的shortDis,根据情况更新shortDis、fatherId
③检查过的节点,更新bIsCheck

功能实现

/* 找到最短距离节点的Id,已经检查的不计算在内 */
def FindShortNodeId(dictNode):
return shortNodeId

/* dikstra算法流程 */
1、找到最短距离节点Id,并标记已检查过 (如果节点Id不存在,表示查找完成)
2、得到最短距离节点的距离
3、轮询最短距离节点的邻居节点
4、计算邻居节点的新距离、得到原最短距离,进行比较
5、如果新距离 < 原距离,则更新邻居节点最短距离
概括为两步:步骤1 (1)- 找到当前最短距离节点
步骤2(2~5) - 更新最短距离节点邻居节点信息

代码实现

import os
import sys

'''
信息输入:
1、节点数目、路由数目
2、路由信息 
3、开始节点、结束节点
'''
nodeNum  = 0   # 节点数目
routeNum = 0   # 路由数目
listRoute = [] # 临时存储输入的路由信息
listNodeId = []# 临时存储节点id 

nodeIdStart = ''
nodeIdEnd   = ''
dictRoute = {}  # 解析后的路由信息
dictNode  = {}  # 节点信息
# 输入节点数目、路由数目
strInput = input()
list0 = strInput.split(' ')
nodeNum  = int(list0[0])
routeNum = int(list0[1])

# 输入路由信息
for index in range(routeNum):
    strInput = input()
    listRoute.append(strInput)
    
# 输入开始节点、结束节点
strInput = input()
list0 = strInput.split(' ')
nodeIdStart = list0[0]
nodeIdEnd   = list0[1]

# 解析得到节点Id
listNodeId.append(nodeIdStart)
listNodeId.append(nodeIdEnd)
for index in listRoute:
    list0 = index.split(' ')
    nodeIdA = list0[0]
    nodeIdB = list0[1]
    if nodeIdA not in listNodeId:
        listNodeId.append(nodeIdA) 
    if nodeIdB not in listNodeId:
        listNodeId.append(nodeIdB) 

# 初始化路由信息字典、节点信息字典
for nodeId in listNodeId:
    # 节点字典信息
    dictNode[nodeId] = [10000, '', False]  # 最短距离、父节点、是否检查过
    # 每个路由字典创建
    dictRoute[nodeId] = {}
dictNode[nodeIdStart][0] = 0

# 初始化路由信息
for index in listRoute:
    list0 = index.split(' ')
    nodeIdA = list0[0]
    nodeIdB = list0[1]
    dictRoute[nodeIdA][nodeIdB] = int(list0[2])
    dictRoute[nodeIdB][nodeIdA] = int(list0[2])
    
# 打印输入信息
def PrintInputInfo():
    print('nodeNum routeNum:')
    print(str(nodeNum) + ' ' + str(routeNum))
    print('nodeStart nodeEnd')
    print(nodeIdStart+' '+nodeIdEnd)
    print('route info:')
    for nodeId in dictRoute.keys():
        for nebrId in dictRoute[nodeId].keys():
            print(nodeId+'->'+nebrId+' = '+str(dictRoute[nodeId][nebrId]))
    print('node info:')
    for nodeId in dictNode.keys():
        print(nodeId+':'+str(dictNode[nodeId][0])+' '+dictNode[nodeId][1]+' '+str(dictNode[nodeId][2]))

#PrintInputInfo()

'''
狄克斯特拉实现
'''
# 找到最短距离节点id
def FindShortNodeId(dictNode):
    shortNodeId = ''
    shortDis = 10000
    for nodeId in dictNode.keys():
        if dictNode[nodeId][0] < shortDis and dictNode[nodeId][2] == False:
            shortNodeId = nodeId
            shortDis    = dictNode[nodeId][0]
    return shortNodeId
    
# 狄克斯特拉算法
shortNodeId = FindShortNodeId(dictNode)
while shortNodeId:
    if shortNodeId == nodeIdEnd:
        break;
    dictNode[shortNodeId][2] = True
    shortDis = dictNode[shortNodeId][0]
    for nebrId in dictRoute[shortNodeId].keys():
        newDis = dictRoute[shortNodeId][nebrId] + shortDis
        if newDis < dictNode[nebrId][0]:
            dictNode[nebrId][0] = newDis
            dictNode[nebrId][1] = shortNodeId
    shortNodeId = FindShortNodeId(dictNode)
    
# 打印结果
listRst = []
nodeId = nodeIdEnd
while nodeId:
    listRst.append(nodeId)
    nodeId = dictNode[nodeId][1]
listRst.reverse()

strRst = ''
for nodeId in listRst:
    if nodeId == listRst[-1]:
        strRst += nodeId
    else:
        strRst += nodeId + '->'

if dictNode[nodeIdEnd][1] == '':
    print('cant reach '+nodeIdEnd)
else:
    print(strRst)
    print(dictNode[nodeIdEnd][0])

测试用例及验证

Case1
输入:
6 4
1 2 2
1 3 4
2 5 3
5 6 2
2 6
在这里插入图片描述

输出:
在这里插入图片描述

Case2
输入:
4 5
S A 6
S B 2
B A 3
A E 1
B E 5
S E
在这里插入图片描述

输出:
在这里插入图片描述

Case3(找不到终点)
输入:
6 6
S A 2
S B 1
A C 4
A B 1
B D 2
C D 3
S End
在这里插入图片描述

输出:
在这里插入图片描述

Case4
输入:
6 8
S A 5
S B 1
A C 1
A B 1
B D 5
C D 1
D End 1
C End 3
S End
在这里插入图片描述

输出:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值