基于 A* 算法的机器人路径规划程序代码实现
Option Explicit
' 定义地图的大小
Const MAP_WIDTH As Integer = 10
Const MAP_HEIGHT As Integer = 10
' 地图数组,0 表示可通行,1 表示障碍物
Dim map(MAP_WIDTH - 1, MAP_HEIGHT - 1) As Integer
' 定义节点结构
Type Node
x As Integer
y As Integer
g As Integer
h As Integer
f As Integer
parentX As Integer
parentY As Integer
End Type
' 开放列表和关闭列表
Dim openList() As Node
Dim closedList() As Node
' 开放列表和关闭列表的当前数量
Dim openListCount As Integer
Dim closedListCount As Integer
' 起点和终点
Dim startX As Integer
Dim startY As Integer
Dim endX As Integer
Dim endY As Integer
' 计算启发式函数(曼哈顿距离)
Function heuristic(x1 As Integer, y1 As Integer, x2 As Integer, y2 As Integer) As Integer
heuristic = Abs(x1 - x2) + Abs(y1 - y2)
End Function
' 判断节点是否在关闭列表中
Function isInClosedList(x As Integer, y As Integer) As Boolean
Dim i As Integer
For i = 0 To closedListCount - 1
If closedList(i).x = x And closedList(i).y = y Then
isInClosedList = True
Exit Function
End If
Next i
isInClosedList = False
End Function
' 判断节点是否在开放列表中
Function isInOpenList(x As Integer, y As Integer) As Boolean
Dim i As Integer
For i = 0 To openListCount - 1
If openList(i).x = x And openList(i).y = y Then
isInOpenList = True
Exit Function
End If
Next i
isInOpenList = False
End Function
' 获取开放列表中 f 值最小的节点索引
Function getLowestFInOpenList() As Integer
Dim i As Integer
Dim lowestIndex As Integer
lowestIndex = 0
For i = 1 To openListCount - 1
If openList(i).f < openList(lowestIndex).f Then
lowestIndex = i
End If
Next i
getLowestFInOpenList = lowestIndex
End Function
' 寻找路径
Function findPath() As Boolean
' 初始化起点
ReDim Preserve openList(0)
openList(0).x = startX
openList(0).y = startY
openList(0).g = 0
openList(0).h = heuristic(startX, startY, endX, endY)
openList(0).f = openList(0).g + openList(0).h
openList(0).parentX = -1
openList(0).parentY = -1
openListCount = 1
Do While openListCount > 0
' 获取开放列表中 f 值最小的节点
Dim currentIndex As Integer
currentIndex = getLowestFInOpenList()
Dim currentNode As Node
currentNode = openList(currentIndex)
' 将当前节点移到关闭列表
closedListCount = closedListCount + 1
ReDim Preserve closedList(closedListCount - 1)
closedList(closedListCount - 1) = currentNode
' 移除开放列表中的当前节点
openListCount = openListCount - 1
If openListCount > 0 Then
openList(currentIndex) = openList(openListCount)
ReDim Preserve openList(openListCount - 1)
End If
' 检查是否到达终点
If currentNode.x = endX And currentNode.y = endY Then
' 找到了路径,重构路径
Dim path() As Node
Dim pathIndex As Integer
pathIndex = 0
ReDim Preserve path(0)
path(0) = currentNode
Do While currentNode.parentX <> -1 And currentNode.parentY <> -1
pathIndex = pathIndex + 1
ReDim Preserve path(pathIndex)
currentNode = closedList(findNodeIndex(currentNode.parentX, currentNode.parentY))
path(pathIndex) = currentNode
Loop
' 反转路径
Dim i As Integer
Dim j As Integer
For i = 0 To pathIndex \ 2
j = pathIndex - i
Dim temp As Node
temp = path(i)
path(i) = path(j)
path(j) = temp
Next i
' 输出路径
For i = 0 To pathIndex
Debug.Print "(" & path(i).x & ", " & path(i).y & ")"
Next i
findPath = True
Exit Function
End If
' 检查相邻节点
Dim neighborX As Integer
Dim neighborY As Integer
For neighborX = currentNode.x - 1 To currentNode.x + 1
If neighborX >= 0 And neighborX < MAP_WIDTH Then
For neighborY = currentNode.y - 1 To currentNode.y + 1
If neighborY >= 0 And neighborY < MAP_HEIGHT And (neighborX <> currentNode.x Or neighborY <> currentNode.y) Then
If map(neighborX, neighborY) = 0 Then
If Not isInClosedList(neighborX, neighborY) Then
Dim newG As Integer
newG = currentNode.g + 1
If isInOpenList(neighborX, neighborY) Then
Dim openIndex As Integer
openIndex = findNodeIndex(neighborX, neighborY)
If newG < openList(openIndex).g Then
openList(openIndex).g = newG
openList(openIndex).f = openList(openIndex).g + openList(openIndex).h
openList(openIndex).parentX = currentNode.x
openList(openIndex).parentY = currentNode.y
End If
Else
openListCount = openListCount + 1
ReDim Preserve openList(openListCount - 1)
openList(openListCount - 1).x = neighborX
openList(openListCount - 1).y = neighborY
openList(openListCount - 1).g = newG
openList(openListCount - 1).h = heuristic(neighborX, neighborY, endX, endY)
openList(openListCount - 1).f = openList(openListCount - 1).g + openList(openListCount - 1).h
openList(openListCount - 1).parentX = currentNode.x
openList(openListCount - 1).parentY = currentNode.y
End If
End If
End If
End If
Next neighborY
End If
Next neighborX
Loop
findPath = False
End Function
' 查找节点在关闭列表中的索引
Function findNodeIndex(x As Integer, y As Integer) As Integer
Dim i As Integer
For i = 0 To closedListCount - 1
If closedList(i).x = x And closedList(i).y = y Then
findNodeIndex = i
Exit Function
End If
Next i
findNodeIndex = -1
End Function
' 主程序入口
Sub Main()
' 初始化地图
map(0, 0) = 0: map(0, 1) = 0: map(0, 2) = 0: map(0, 3) = 0: map(0, 4) = 0
map(1, 0) = 0: map(1, 1) = 1: map(1, 2) = 0: map(1, 3) = 0: map(1, 4) = 0
map(2, 0) = 0: map(2, 1) = 1: map(2, 2) = 0: map(2, 3) = 0: map(2, 4) = 0
map(3, 0) = 0: map(3, 1) = 1: map(3, 2) = 0: map(3, 3) = 0: map(3, 4) = 0
map(4, 0) = 0: map(4, 1) = 0: map(4, 2) = 0: map(4, 3) = 0: map(4, 4) = 0
' 设置起点和终点
startX = 0
startY = 0
endX = 4
endY = 4
' 寻找路径
If findPath() Then
Debug.Print "找到路径"
Else
Debug.Print "没有找到路径"
End If
End Sub
时间复杂度分析
- 在最坏情况下,A* 算法可能需要扩展地图上的每一个节点。假设地图规模为 (N \times M),则节点数量为 (NM)。
- 每次从开放列表中选择 f 值最小的节点时,需要遍历开放列表,时间复杂度为 (O(openListCount)),在最坏情况下,开放列表可能包含所有节点,即 (O(NM))。
- 因此,A* 算法的时间复杂度在最坏情况下为 (O(NM)),这里的 (N) 和 (M) 分别是地图的行数和列数。
空间复杂度分析
- 空间复杂度主要取决于开放列表和关闭列表。
- 在最坏情况下,开放列表和关闭列表可能包含地图上的所有节点,即 (O(NM)),这里 (N) 和 (M) 分别是地图的行数和列数。
- 因此,A* 算法的空间复杂度为 (O(NM))。
算法优化以适应大规模地图
- 使用更高效的数据结构:开放列表可以使用优先队列(如二叉堆)来代替简单的数组,这样每次获取 f 值最小的节点时间复杂度可以降低到 (O(\log(openListCount))),从而提高整体算法效率。
- 分层规划:将大规模地图划分为多个较小的子地图,先在子地图层面进行路径规划,得到一个大致的路径框架,然后在子地图内部进行详细的路径规划。这样可以减少搜索空间。
- 启发式函数优化:使用更精确的启发式函数,例如在一些情况下使用欧几里得距离代替曼哈顿距离作为启发式函数,使搜索更有针对性,减少不必要的节点扩展。
- 双向搜索:从起点和终点同时开始搜索,当两个搜索相遇时,即找到路径。这样可以减少搜索空间,提高搜索效率。