|

楼主 |
发表于 2012-12-28 15:50
|
显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件 ★ 免费下载 ★ ★ 使用帮助★
正确的Dijkstra算法
本帖最后由 lee1892 于 2013-1-4 15:01 编辑
正确的Dijkstra算法
实际的例子
以HHAAMM在其贴中给的例子为例,设置自定义数据类型和节点集合如下:[code=vb]
Private Type NODE_INFO
Name As String ' 节点名称
Connects() As Long ' 可连接的节点地址,节点数组的下标
Distances() As Double ' 与所连接节点的距离
Previous As Long ' 查找时的前驱节点
TotalDist As Double ' 查找时距离起始点的总距离
End Type
Private aNodes() As NODE_INFO ' 节点数组
Private cNodeHash As Collection ' 集合模拟散列表,用名称索引节点数组下标
[/code]而实现Dijkstra算法的代码则是:[code=vb]
Private Sub Dijkstra(sBegin$, sEnd$)
Dim dTempNodes As Object, aItems
Dim i&, j&, nIndex&, nNodeIndex&
' 使用字典对象建立临时节点集合
Set dTempNodes = CreateObject("scripting.dictionary")
For i = 1 To UBound(aNodes)
aNodes(i).Previous = -1 ' 标记为未定义
aNodes(i).TotalDist = -1 ' 负值代表无穷大
dTempNodes(aNodes(i).Name) = i
Next
aNodes(cNodeHash(sBegin)).TotalDist = 0 ' 起始点的初始总距离为 0,即起始点到起始点的距离
Do While dTempNodes.Count > 0 ' 临时节点集合为空则退出
' 总是从临时节点集合中获得总距离最小的那个节点作为当前节点,并从临时集合中删除
aItems = dTempNodes.Items: nIndex = LBound(aItems)
For i = LBound(aItems) To UBound(aItems)
If aNodes(aItems(i)).TotalDist >= 0 Then
If aNodes(aItems(nIndex)).TotalDist < 0 Then
nIndex = i
ElseIf aNodes(aItems(i)).TotalDist < aNodes(aItems(nIndex)).TotalDist Then
nIndex = i
End If
End If
Next
nNodeIndex = aItems(nIndex)
' 此处可以添加判断,如果获得的当前节点是终点的话,即可退出循环
' 否则会遍历所有节点,并使得所有节点都保留了至起始点最短路径的前驱节点和总距离
If aNodes(nNodeIndex).Name = sEnd Then Exit Do
dTempNodes.Remove aNodes(nNodeIndex).Name
' 对于当前节点,遍历其可连接的节点(不在临时集合中)
' 如果其可连接的节点的总距离大于当前节点的总距离+两者之间的距离,
' 则将其更新为后者,并将该节点的前驱节点设为当前节点
With aNodes(nNodeIndex)
For j = 1 To UBound(.Connects)
If Not dTempNodes.exists(aNodes(.Connects(j)).Name) Then GoTo NEXT_CONNECTION
If aNodes(.Connects(j)).TotalDist < 0 Then
aNodes(.Connects(j)).TotalDist = .TotalDist + .Distances(j)
aNodes(.Connects(j)).Previous = nNodeIndex
ElseIf aNodes(.Connects(j)).TotalDist > .TotalDist + .Distances(j) Then
aNodes(.Connects(j)).TotalDist = .TotalDist + .Distances(j)
aNodes(.Connects(j)).Previous = nNodeIndex
End If
NEXT_CONNECTION:
Next
End With
Loop
dTempNodes.RemoveAll
Set dTempNodes = Nothing
End Sub
[/code]那么对于查找结束后的路径的获得,则是由终点通过保留的前驱节点向起始点搜索,代码如下,其中Initialize是数据初始化过程,Terminate则是清空全局变量用的:[code=vb]
Private Sub btnFind_Click()
Dim nEnd&, sRoutine$, dDistance#
If cNodeHash Is Nothing Then Call Initialize
Call Dijkstra([G10], [G11])
' 从终点按前驱节点链接到达起始点即所查找的最短路径
nEnd = cNodeHash([G11])
sRoutine = aNodes(nEnd).Name
dDistance = aNodes(nEnd).TotalDist
Do
nEnd = aNodes(nEnd).Previous
sRoutine = aNodes(nEnd).Name & "->" & sRoutine
If aNodes(nEnd).Previous < 0 Then Exit Do
Loop
[G13] = sRoutine & " " & Round(dDistance, 2)
Call Terminate
End Sub
[/code]附件在1楼
|
|