一、贪婪最佳优先搜索算法
1、引言
无信息搜索算法,如广度优先搜索(BFS)和深度优先搜索(DFS),这些算法在探索状态空间时,除了问题定义本身提供的状态转移规则外,没有任何额外的信息来判断一个非目标节点比另一个“更有希望”接近目标。因此,它们通常是盲目地进行搜索。
为了提高搜索效率,我们引入了启发式搜索算法,也称为有信息搜索。这类算法利用与问题相关的启发式信息来引导搜索方向,优先选择那些看起来最接近目标的节点进行扩展。
贪婪最佳优先搜索算法是启发式搜索中最简单、最直观的一种。它的核心思想非常朴素:在每一步选择中,都选择那个离目标估计最近的节点进行扩展,而完全忽略到达该节点已经付出的代价。这种只顾眼前最优(看起来离目标最近)而不考虑历史代价的策略,体现了其“贪婪”的本质。
2、核心思想与评估函数
为了能够评估一个节点距离目标的“远近”,我们引入一个启发式函数(Heuristic Function),记为
需要强调的是,
贪婪最佳优先搜索算法使用一个评估函数
这个定义清晰地揭示了算法的贪婪特性:它唯一关心的就是启发函数
3、算法流程
贪婪最佳优先搜索算法通常使用一个优先队列来管理待访问的节点集合(通常称为“开放列表”或 OPEN list),队列中的节点按照其 CLOSED list)。
算法伪代码:
-
初始化:
- 创建一个优先队列
OPEN,用于存放待扩展的节点。 - 创建一个集合
CLOSED,用于存放已访问的节点。 - 将起始节点
start放入OPEN中。
- 创建一个优先队列
-
循环搜索:
- WHILE
OPEN不为空 DO- 从
OPEN中取出值最小的节点 。 - IF
是目标节点 THEN - 搜索成功。从节点
回溯其父节点,构造并返回路径。
- 搜索成功。从节点
- 将节点
从 OPEN移出,并放入CLOSED中。 - FOR 节点
的每一个后继节点 DO - IF
不在 OPEN中 AND不在 CLOSED中 THEN- 设置
的父节点为 。 - 计算
的启发式评价值 。 - 将
加入 OPEN。
- 设置
- IF
- 从
- WHILE
-
搜索失败:
- IF
OPEN为空 AND 还没有找到目标节点 THEN- 搜索失败,返回
Failure。
- 搜索失败,返回
- IF
4、应用
让我们通过一个经典的路径规划问题来具体演示贪婪最佳优先搜索的执行过程。
问题描述:
假设我们有一个如下图所示的地图,我们的任务是从城市
启发式函数值
| 节点 | |||||||
|---|---|---|---|---|---|---|---|
| 10 | 7 | 8 | 4 | 6 | 2 | 0 |
算法执行步骤:
步骤 0:初始化
OPEN=CLOSED=
步骤 1:
OPEN非空。从中取出值最小的节点,当前只有 。 - 当前节点
。 不是目标节点 。 - 将
从 OPEN移至CLOSED。OPEN=CLOSED=
- 扩展
的后继节点 和 。 - 节点
:不在 OPEN或CLOSED中。计算。将其加入 OPEN。 - 节点
:不在 OPEN或CLOSED中。计算。将其加入 OPEN。
- 节点
- 状态更新:
OPEN=( 的 值更小,排在前面) CLOSED=
步骤 2:
OPEN非空。从中取出值最小的节点 。 - 当前节点
。 不是目标节点 。 - 将
从 OPEN移至CLOSED。OPEN=CLOSED=
- 扩展
的后继节点 。 - 节点
:不在 OPEN或CLOSED中。计算。将其加入 OPEN。
- 节点
- 状态更新:
OPEN=( 的 值更小,排在前面) CLOSED=
步骤 3:
OPEN非空。从中取出值最小的节点 。 - 当前节点
。 不是目标节点 。 - 将
从 OPEN移至CLOSED。OPEN=CLOSED=
- 扩展
的后继节点 和 。 - 节点
:不在 OPEN或CLOSED中。计算。将其加入 OPEN。 - 节点
:不在 OPEN或CLOSED中。计算。将其加入 OPEN。
- 节点
- 状态更新:
OPEN=( 的 值最小) CLOSED=
步骤 4:
OPEN非空。从中取出值最小的节点 。 - 当前节点
。 是目标节点! - 搜索成功!
路径回溯:
的父节点是 。 的父节点是 。 的父节点是 。 - 最终找到的路径为:
。
二、A* 搜索算法
1、引言
贪婪最佳优先搜索算法完全依赖于启发式信息
一个自然而然的问题是:我们能否将这两种方法的优点结合起来?即,既利用启发式信息来加速搜索,又考虑已经付出的代价来保证最优性?
答案是肯定的。A* 搜索算法正是为此而生。它通过一个精巧的评估函数,完美地平衡了“已付出的代价”和“对未来的估计”,成为路径搜索中最著名、最广泛应用的算法之一。A* 算法可以被看作是 Dijkstra 算法的扩展,增加了启发式引导;也可以看作是贪婪最佳优先搜索的改进,增加了对历史代价的考量。
2、核心思想与评估函数
A* 算法的核心在于其独特的评估函数
其中:
: 是从起始节点到节点 的实际最小代价。这与 Dijkstra 算法中的考量完全一致。 : 是从节点 到目标节点的估计代价,即我们已经熟悉的启发式函数。
因此,评估函数
A* 算法在每一步选择中,都会优先扩展 OPEN 列表中
- 如果只看
,算法退化为 Dijkstra 算法。 - 如果只看
(即令 ),算法退化为贪婪最佳优先搜索。
通过同时考虑
3、算法流程
A* 算法的流程与贪婪最佳优先搜索非常相似,同样使用优先队列 OPEN 和集合 CLOSED。关键区别在于优先队列的排序依据从
算法伪代码:
-
初始化:
- 创建一个优先队列
OPEN,用于存放待扩展的节点,按值升序排列。 - 创建一个集合
CLOSED,用于存放已访问的节点。 - 创建起始节点
start,设置其g(start) = 0,计算f(start) = g(start) + h(start) = h(start)。- 将起始节点
start放入OPEN中。
- 将起始节点
- 创建一个优先队列
-
循环搜索:
-
WHILE
OPEN不为空 DO- 从
OPEN中取出值最小的节点 。 - IF
是目标节点 THEN - 搜索成功。从节点
回溯其父节点,构造并返回路径。
- 搜索成功。从节点
- 将节点
从 OPEN移出,并放入CLOSED中。 - FOR 节点
的每一个后继节点 DO - IF
在 CLOSED中 THEN- 跳过,因为已经找到了从起点到
的最优路径。
- 跳过,因为已经找到了从起点到
- 计算从起点经过
到达 的新路径代价: 其中 是从 到 的边代价。 - IF
不在 OPEN中 ORTHEN - 设置
的父节点为 。 - 更新
的代价: 。 - 计算
的评估值: 。 - IF
不在 OPEN中 THEN- 将
加入 OPEN。
- 将
- ELSE
- (在
OPEN中)更新的优先级。
- (在
- 设置
- IF
- 从
-
-
搜索失败:
- IF
OPEN为空 AND 还没有找到目标节点 THEN- 搜索失败,返回
Failure。
- 搜索失败,返回
- IF