欢迎访问宙启技术站
智能推送

python 实现A*算法的示例代码

发布时间:2023-05-17 18:18:10

A*算法是一种启发式搜索算法,经常用于路径规划问题中。它的特点是能够快速搜索出一条路径,并且保证路径是最优解或者是最优解的近似解。在本文中,我们将介绍如何使用Python来实现A*算法,并给出一个简单的示例代码。

1. A*算法的基本思路

A*算法是一种基于优先级搜索的算法,其基本思路如下:

1.1 定义启发函数f(n)

在A*算法中,启发函数被定义为f(n)。它用于评估每个节点n的优先级。f(n)的计算方式通常有两种:

- f(n) = g(n) + h(n)

其中g(n)是从起始节点到节点n的实际距离(也称为实际代价),h(n)是从节点n到目标节点的估计距离(也称为启发代价)。h(n)是一种估价函数,它并不是节点n到目标节点的实际距离,而是基于一些启发式的方法进行计算的。在A*算法中,h(n)必须满足以下条件:

- h(n) >= 0

- h(n) <= h*(n)

其中h*(n)是节点n到目标节点的实际距离或者是实际代价的上界。通常情况下,h*(n)不能超过实际距离的两倍。

- f(n) = g(n)

在某些情况下,节点n到目标节点的距离是已知的,此时可以将f(n)简化为g(n)。例如,在棋盘上搜索,如果每个节点都是正方形,则h(n)等于从节点n到目标节点的最短曼哈顿距离。此时,f(n)可以表示为:

f(n) = g(n) + h(n),

其中:

g(n)表示在起点创建节点n的代价,

h(n)表示节点n到终点的最短距离(曼哈顿距离)。

另一方面,如果每个节点不是一个正方形,则用勾股定理计算代价。

1.2 初始化起始节点和目标节点

我们需要先初始化起始节点(也称为起点)和目标节点(也称为终点)。这两个节点可以通过在地图上点选或者手动指定。在A*算法中,起始节点是起点,目标节点是终点。每次搜索都是从起点开始,直到到达终点为止。

1.3 将起始节点加入开放列表

开发列表是用于存储搜索结果的数据结构。在A*算法中,开放列表是一个按优先级排序的节点列表。搜索从起点开始,从开放列表中取出优先级最高的节点。由于起点本身是一个节点,所以我们需要将起始节点加入开放列表。

1.4 开始搜索

在搜索过程中,我们需要不断取出开放列表中优先级最高的节点,直到到达终点。在取出一个节点n之后,我们将其加入关闭列表(已访问节点列表)。然后,我们需要找到所有与节点n相邻的节点,并计算它们的f(n)值。对于每个相邻节点k,如果它没有被访问过,将其添加到开放列表中。

1.5 判断节点是否已被访问过

节点是否已经被访问过,可以通过检查其是否在关闭列表中进行判断。如果节点n已经在关闭列表中,则说明我们已经找到了从起点到节点n的最短路径。

1.6 计算路径

在每次访问节点时,我们需要计算从起点到当前节点的路径。对于当前节点k,其所有祖先节点(也称为父节点)可以通过从k的父节点开始递归计算而得到。直到到达起点为止。如果我们找到了从起点到终点的最短路径,在计算完成后,我们可以从终点开始递归,找到所有的祖先节点,并将其组成一条路径。

2. Python实现

下面,我们将使用Python来实现A*算法,代码示例如下:


from queue import PriorityQueue

def astar(start, goal, successor, heuristic):
    # create open and closed lists
    open_list = PriorityQueue()
    closed_list = set()
    # initialize start node
    start_node = {"parent": None, "position": start, "g": 0, "f": 0}
    open_list.put((0, id(start_node), start_node))
    # search the path
    while not open_list.empty():
        # get the node with the highest priority
        current_node = open_list.get()[2]
        # check if the goal is reached
        if current_node["position"] == goal:
            # construct the path
            path = []
            while current_node:
                path.append(current_node["position"])
                current_node = current_node["parent"]
            return path[::-1]
        # add current node to closed list
        closed_list.add(id(current_node))
        # generate successor nodes
        for next_node in successor(current_node["position"]):
            # calculate g and f values
            new_g = current_node["g"] + 1
            new_f = new_g + heuristic(next_node, goal)
            next_node_dict = {"parent": current_node, "position": next_node, "g": new_g, "f": new_f}
            next_node_id = id(next_node_dict)
            # check if next node is already explored
            if next_node_id in closed_list:
                continue
            # check if next node is already in the open list
            for _, _, node in open_list.queue:
                if id(node) == next_node_id and next_node_dict["g"] > node["g"]:
                    continue
            # add next node to the open list
            open_list.put((new_f, next_node_id, next_node_dict))
    # if the open list is empty and goal is not reached
    return None

# example usage
start = (0, 0)
goal = (5, 7)

def manhattan_distance(a, b):
    return abs(a[0] - b[0]) + abs(a[1] - b[1])

def successor(node):
    x, y = node
    candidates = [(x+1, y), (x-1, y), (x, y+1), (x, y-1)]
    return [(x, y) for x, y in candidates if 0 <= x < 6 and 0 <= y < 8]

path = astar(start, goal, successor, manhattan_distance)
print(path)

在这个示例中,我们需要传入四个参数。start和goal分别代表起点和终点。successor是一个函数,用于生成与节点相邻的所有节点。heuristic是一个估价函数,用于评估节点与目标节点之间的距离。在示例中,我们使用了曼哈顿距离作为估计距离。同时在函数中,我们定义了一个open_list和closed_list,分别用于存储已经访问和未访问的节点。

3. 小结

本文介绍了A*算法的基本思路和Python实现。虽然这个算法在路径规划中被广泛使用,但是实现起来并不复杂。通过使用Python优秀的数据结构和算法库,我们可以很容易地实现一个高效的路径规划算法。