经典搜索算法总结-程序员宅基地

技术标签: 算法  算法与数据结构  

前言

搜索问题是在解决各类问题时不可避免的重点难点,很多问题的求解过程都可以转变为搜索问题。比如,对于以下罗马尼亚问题,希望找到一条路径使得从城市 Arad 到城市 Bucuresti 的路径最短,这就是一个经典的搜索问题,在数据结构课程中,我们都知道使用 Dijkstra 算法来求得最优解,受《人工智能 一种现代化的方法》这本书的影响,本博客则以此为基石通过更一般的方法来讨论通用的搜索问题的求解思路。
在这里插入图片描述


0x1 搜索问题的形式化

一个搜索问题可以通过五个元素给出形式化的定义:

  • 初始状态。状态用 s 表述,初始状态也是状态的一种,上述罗马尼亚问题的初始状态可以描述为 In(Arad)
  • 可能的行动。行动用 a 表述,对于一个特殊状态 sACTIONS(s) 返回在状态 s 下可以执行的动作集合。例如,在状态 In(Arad) 下可能的行动为: {Go(Sibiu), Go(Timisoara), Go(Zerind)}
  • 转移模型。转移模型用 RESULT(s, a) 表述,表示在状态 s 下执行行动 a 后达到的状态。通常也用术语后继状态来表示从一给定状态出发通过单步行动可以到达的状态集合。例如:RESULT(In(Arad), Go(Zerind)) = In(Zerind)
  • 目标测试。确定给定的状态是不是目标状态。在罗马尼亚问题中,目标状态集是一个单元素集合 {In(Bucuresti)}
  • 路径代价。采用行动 a 从状态 s 走到状态 s’ 所需要的单步代价表述为 c(s,a,s'),路径代价就代表从初始状态到目标状态的单步代价总和。

通过形式化的定义搜索问题,则搜索问题的解描述为一组让初始状态转变为目标状态的行动序列,而搜索问题的最优解描述为使得路径代价最小的一组让初始状态转变为目标状态的行动序列。


0x2 树搜索和图搜索

在对问题进行形式化后,需要对问题求解,而一个解就是一个行动序列,所以搜索算法的工作的就是考虑各种可能的行动序列。可能的行动序列从搜索树中根结点的初始状态出发,连线表示行动,结点对应问题的状态空间中的状态。

树搜索算法
例如在罗马尼亚问题中,从父结点 In(Arad) 出发得到三个子结点:In(Sibiu)In(Timisoara)In(Zerind),接下来需要继续从这三种子结点中选择其一继续考虑,假设我们选择 In(Sibiu) ,则检查它是否是目标状态,如果不是目标状态,则继续扩展它得到四个状态:In(Arad)In(Fagaras)In(Oradea)In(Rimnicu Vikea)。继续按此方式拓展 In(Timisoara)In(Zerind) 。如果未找到目标状态,则继续对叶子结点作同样的操作,如下图:
在这里插入图片描述

此时引入两个概念:
frontier 结点:frontier 结点是指所有还没有扩展的搜索结点
explored 结点:explored 结点是指所有已经扩展的搜索结点

注意到在拓展 In(Sibiu) 的时候,将 In(Arad) 结点也加入了 frontier 集合,而此时 In(Arad) 结点已经是拓展过的结点,已经加入了 explored 集合。同时在扩展 In(Zerind) 结点的时候,将 In(Oradea) 结点也加入了 frontier 集合,而此时 In(Oradea) 结点本身已经在 frontier 集合中了,这个特别也是树搜索的精髓所在。树搜索的算法伪代码如下:
在这里插入图片描述
图搜索算法
对于上述罗马尼亚问题,采用图搜索算法生成的树如下:
在这里插入图片描述
在图搜索算法中,在扩展的时候如果遇到已经在 explored 集合中的结点或已经在 frontier 集合中的结点,则不将该结点拓展进 frontier 集合,这也是其与树搜索算法的主要区别。图搜索的算法伪代码如下:
在这里插入图片描述


0x3 搜索算法的评估

通常一个搜索算法用三个指标来进行评估:

  • 完备性:当问题有解时,这个算法是否可以保证找到解?
  • 最优性:当问题有解时,这个算法是否可以找到使得路径代价最小的解?
  • 复杂性:时空复杂度。

在搜索算法中,是什么决定了搜索策略?
由于搜索算法重复的从 frontier 集合中选择和移除一个结点,并且拓展该结点并且将拓展结点插入到 frontier 集合中。如果每次从 frontier 集合的固定位置选取结点,则搜索策略由结点在 frontier 中的顺序决定


0x4 盲目搜索策略

盲目搜索算法不会考虑结点离目标有多远,除了问题定义中提供的状态信息外没有任何其他附加信息!

0x4.1 宽度优先搜索算法BFS

宽度优先搜索算法(图搜索)的思路就和数据结构中的 BFS 是一个东西。其首先在 frontier 集合中找到最先进入该集合的结点,然后将该结点加入到 explored 集合,同时拓展该节点得到他的每个子结点,对于每个子结点,如果该子结点不在 frontier 集合和 explored 集合中且不是要找到目标结点,则将子结点加入到 frontier 集合中,如此循环直到 frontier 集合为空或者找到目标结点为止。BFS(图搜索)算法伪代码如下:
在这里插入图片描述
显然提前测试可以减少遍历的结点数,如果等到从 frontier 集合中弹出时再测试,那么需要拓展很多不必要的结点。通过将 frontier 集合设计成队列,采用先进先出的策略则可以实现 BFS。
BFS 算法评估(设分支因子为 b,最浅的目标结点的深度为 d):

  • 完备性:当树的分支因子 b 是有限的,则算法是完备的。
  • 最优性:如果路径代价是基于结点深度的非递减函数,则算法是最优的,否则不具备最优性。
  • 复杂性:显然时空复杂度均为 O(bd)

0x4.2 一致代价搜索算法UCS

一致代价搜索算法(图搜索)的思想就类似于 Dijkstra 算法。其首先在 frontier 集合中找到当前代价最低的结点,判断该结点是否是目标结点,如果是,则返回解,否则将该结点加入到 explored 集合中,然后拓展该结点得到他的每个子结点。对于每个子结点,如果该子结点不在 frontier 集合和 explored 集合中,则将该子结点加入到 frontier 集合中;否则如果该子结点在 frontier 集合中,但是其代价比已经在 frontier 集合中的低,则用新生成的子结点代替原来 frontier 集合的子结点。UCS(图搜索)算法伪代码如下:
在这里插入图片描述
UCS 在结点被拓展时才进行目标检测,这是与 BFS 最大的区别,因为第一次生成的目标的结点可能在次优路径上。通过将 frontier 集合设计成优先级队列,则可以实现 UCS。
UCS 算法评估(设分支因子为 b,某个小的正值 ξ,最优解的代价 C*):

  • 完备性:如果存在零代价的行动则可能陷入死循环,但如果每一步的代价都大于等于 ξ,则算法是完备的。
  • 最优性:显然具有最优性
  • 复杂性:时空复杂度均为 O(b^(1+ ⌊ C ∗ / ξ ⌋ \lfloor C^*/ξ \rfloor C/ξ))

0x4.3 深度优先搜索算法DFS

深度优先搜索算法(图搜索)的思路类似于数据结构中的DFS。其基本思想是首先在 frontier 集合中找到最后进入该集合的结点,然后将该结点加入到 explored 集合,同时拓展该节点得到他的每个子结点,对于每个子结点,如果该子结点不在 frontier 集合和 explored 集合中且不是要找到目标结点,则将子结点加入到 frontier 集合中,如此循环直到 frontier 集合为空或者找到目标结点为止。DFS 和 BFS 最大的区别在于对 frontier 集合中结点的选取,BFS 中对结点的选取符合先进先出的策略,而 DFS 中对结点的选取则符合先进后出的策略,所以 DFS 可以用栈来实现其 frontier 集合。DFS 算法有一个很重要的特别就是其及其依赖采取的是树搜索还是图搜索,因为树搜索每次都可能会加入重复的结点,这样就会导致在两个重复的结点之间无线循环。
DFS 算法评估(设分支因子为 b,最浅的目标结点的深度为 d,最深的叶子结点为 m):

  • 完备性:对于树搜索,DFS 总是不完备的;而对于图搜索,DFS 在有限状态空间下是完备的,而在无限状态空间下是不完备的。
  • 最优性:显然不是最优的
  • 复杂性:时间复杂度为 O(bm),空间复杂度为 O(bm),可见其空间复杂度比上述两种搜索小很多,这也是深度优先搜索最大的优势。

0x4.4 深度受限搜索DLS

对于无限状态空间深度优先搜索算法总是会失败,而这个问题可以通过对深搜设定界限 l 来避免,也就是说在深搜的,当深度达到了 l ,则采取舍弃更深结点的策略。其算法可以采用基于递归的方式来实现,算法的伪代码如下:
在这里插入图片描述
DLS 算法评估(设分支因子为 b,限定的深度为 l,最浅的目标结点的深度为 d):

  • 完备性:显然当 l < d 的时候,DLS 则总是不完备的。
  • 最优性:即使当 l > d 的时候,根据 DFS 算法,DLS 也不是最优的。
  • 复杂性:时间复杂度为 O(bl),空间复杂度为 O(bl)

0x4.5 迭代加深搜索IDS

在 DLS 算法中,我们无法选取一个合适的深度 l 来求解,这就是 IDS 的动机,在未找到解之前不断的增加 l ,迭代的使用 DLS 算法,当 l 达到最浅的目标结点的深度 d 时,则可以求出解。其算法伪代码如下:
在这里插入图片描述
IDS 算法评估(设分支因子为 b,限定的深度为 l,最浅的目标结点的深度为 d):

  • 完备性:当分支因子是有限的的时候,IDS 是完备的
  • 最优性:类似于宽度优先搜索算法,如果路径代价是基于结点深度的非递减函数,则算法是最优的。
  • 复杂性:时间复杂度为 O(bd),空间复杂度为 O(bd)

0x4.6 双向搜索算法

双向搜索算法思想则是同时运行两个搜索——一个从初始状态向前搜索同时另外一个从目标状态向后搜索——希望他们在中间某个结点相遇,此时搜索停止。理由是,比如两边都采用宽度优先搜索,则显然 bd/2+bd/2 要远小于 bd

0x4.7 六种搜索算法的对比

在这里插入图片描述


0x5 启发式搜索策略

在盲目搜索策略中,往往不考虑结点离目标有多远,也就是说,在搜索的过程中,并不考虑目标的状态对当前搜索行为的影响,而仅仅依赖于当前的状态;比如在罗马尼亚问题中,从城市 Arad 到城市 Bucuresti 的搜索,仅仅只考虑在当前状态下可能导致的代价,该策略虽然能搜索到最优解,但是在搜索过程中可能会有很多不必要的操作,因为搜索的结果只关注那条最优的路径,但是实际在搜索的过程中可能会搜索到与最优路径无关的结点。而启发式搜索策略则不一样,他会考虑目标状态对当前状态的影响,这样做使得在搜索的过程中更大的可能搜索和最优路径相关的状态,减少不必要的搜索,增加搜索的效率,比如说在罗马尼亚问题中,可以在考虑代价的同时,还考虑当前结点离目标结点的直线距离来选取下一个要拓展的结点,而这个直线距离就作为启发式的信息来帮助搜索的决策,以此更快地搜索到最优路径。
在启发式搜索中,通常用 g(n) 表示结点 n 当前的代价,用 h(n) 表示启发函数,一般来说 h(n) = 结点 n 到目标结点的最小代价路径的代价估计值(比如在罗马尼亚问题中可以用 AradBucuresti 的直线距离来作为从 AradBucuresti 的最小代价路径的代价估计值),用 f(n) 作为选择结点的代价评估值,f(n)=g(n)+h(n) ,当 f(n) 越小,则代表结点越优;启发式搜索对扩展结点的选择同时依赖于 g(n) 和 h(n),对于 h(n) 较小的结点,我们可以认为该结点会让我们离目标结点更近,所以 h(n) 作为启发式的信息能帮助我们在搜索的时候做出决策。

0x5.1 贪婪最佳优先搜索GBFS

贪婪最佳优先搜索算法试图扩展离目标最近的结点,理由是这样可能可以很快找到解,因此,它只用启发式信息,即 f(n)=h(n)。还是对于上述的罗马尼亚问题,通过 GBFS 算法求解的路径如下,可见该算法并不是最优的。
在这里插入图片描述
GBFS 算法评估(设分支因子为 b,最深的叶子结点为 m):

  • 完备性:当状态空间是无限的时候,GBFS 是不完备的;当状态空间是有限的,图搜索的 GBFS 算法是完备的,而树搜索的 GBFS 算法是不完备的。
  • 最优性:显然不是最优的。
  • 复杂性:时间复杂度为 O(bm),空间复杂度为 O(bm),因为要保存所有的结点在内存中。

0x5.2 A*搜索

在 GBFS 算法中,仅仅采用启发式作为评估值,导致不能求到最优解,A* 搜索算法同时考虑到代价,以期解决 GBFS 算法中的问题,因此 A* 搜索采用的代价评估值 f(n) 为 h(n) 与 g(n) 的和,其算法伪代码的实现如下:
在这里插入图片描述
A* 算法一定能找到最优的路径吗?考虑如下的例子:
在这里插入图片描述
假设从 S 走到 G ,那么在 S 结点扩展后,frontier 里面剩下 A(其代价估计 f(A) 为 7)和 G (其代价估计 f(G) 为 5),那么根据 A* 算法,会从 frontier 里面选取 G,此时得到解,但可以发现在这种情况下显然求到的不是最优解,这是因为在 A 结点出其启发式的值过于高,明显的大于其到 G 结点的真是代价,导致产生不准确的估计,所以我们的思路就是降低 A 结点的 h 到一个合适的值,在此处若 h(A) 比 4 小的话则可以根据 A* 算法求到最有解。此处引入一个新的概念——可采纳性

  • 可采纳性:假设 h*(N) 是从 N 结点到目标结点的最优路径的代价, 当启发式函数 h(N) 满足以下不等式的时候,我们称该 h(N) 是可采纳的 (admissible) ——0 ≤ \le h(N) ≤ \le h*(N)

在引入可采纳性后,A* 算法在树搜索和图搜索下都具有最优性吗?同样考虑以下的例子:
在这里插入图片描述
该问题的启发式函数是可采纳的,假设从 A 走到 E,可以发现在树搜索的情况下找到最优解,而在图搜索的情况下却没有找到最优解。这是因为图搜索在遇到已经加入到 explored 集合的结点的时候,会直接不考虑该结点,导致可能不能修正之前扩展带来的错误,比如在上例中,树搜索在扩展右边的 D 结点后,在扩展 B 结点的时候将左边的 D 结点加入到了 frontier 里面,从而有机会修正一开始扩展的右边的 D 结点,使得算法找到最优解;而图搜索由于在第一次扩展 D 结点后,其加入到 explored 结点,导致第二次遇到估计代价更低的 D 结点时,直接将其抛弃而不加入到 frontier 结点,所以会找不到最优解。从这里可以看出,在图搜索算法中,如果结点被加入到了 explored 集合,则算法认为当前在 explored 集合中的路径一定会是最优路径的子路径(类似于 UCS 算法),其实并不是,这就导致无法像树搜索那行修正路径导致无法找到最优解。但是,如果给启发式函数加入比可采纳性更强的约束,会不会使得图搜索也是最优的呢?此处引入一个新的概念——一致性

  • 一致性:如果对于每个结点 N 和通过任一行动 a 生成的 N 的每个后继结点 N’,从结点 N 到达目标的估计代价不大于从 N 到 N’ 的单步代价与从 N’ 到达目标的估计代价之和,我们称启发式函数 h(N) 具有一致性 。即满足不等式 —— h(N) ≤ \le c(N, a, N’)+h(N’) 。显然一致性会使得启发式函数更小,也就说一致的启发式函数一定是可采纳的。

当启发式函数满足一致性的时候,则 A* 图搜索算法是最优的。

A* 算法评估(设 C* 是最优解路径的代价值,分支因子为 b,最浅的目标结点的深度为 d):

  • 完备性: A* 算法会扩展所有代价评估值 f(n) 小于 C* 的结点,但不会扩展代价评估值 f(n) 大于 C* 的结点,所以当代价小于等于 C* 的结点是有穷的,则 A* 算法是完备的。
  • 最优性:A* 算法的最优性依赖于其是树搜索还是图搜索,启发式函数是否是可采纳的,一致的。如下图:

在这里插入图片描述

  • 复杂性:在所有的可以找到最优解的搜索算法里面,A* 搜索的效率是最高的,因为这些算法里面他们都会扩展所有代价评估值 f(n) 小于 C* 的结点,但是 A* 算法一定不会扩展代价评估值 f(n) 大于 C* 的结点,这样使得 A* 算法访问的结点更少,求解的速度更快。时间复杂度和空间复杂度为 O(bd)

由以上讨论可知,A* 算法对于任何给定的一致的启发式函数都是效率最优的,所以设计 A* 算法,最关键的就是设计启发式函数 h(n) 。

既然让启发式函数值更小,会让 A* 算法更可能达到一致性,那是不是启发式函数值越小越好呢?显然不是,对于两个一致的启发式函数 h1 和 h2 ,若 h1(N) > h2(N) ,我们则称 h1 更准确,采用 h1 会使得求解过程更快。也就是说我们期望的启发式函数,是在满足一致性的前提下,越大越好!!具体的设计启发式函数的时候可以从松弛问题出发,也可以从子问题出发,也可以从学习的角度出发,具体细节的在此处就不讨论了(逃),可以参考由我们任课老师翻译的 AI 原理神书 —— 《人工智能 一种现代的方法》!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_21746331/article/details/117405789

智能推荐

请使用c++通过遗传算法解决旅行商问题-程序员宅基地

文章浏览阅读60次。我可以向您提供关于使用遗传算法解决旅行商问题的一些指导。首先,需要确定旅行商问题的地图数据,然后编写代码,创建一个遗传算法,然后对算法进行调优,以获得最佳路线。最后,将结果显示在地图上,以便查看最终路线。...

学习JAVA游戏服务器开发需要了解的情况_java游戏服务器开发用到数据库吗-程序员宅基地

文章浏览阅读1.3w次,点赞21次,收藏85次。一,游戏服务器开发的工作介绍近来遇到有很多人想从其它开发领域转到游戏服务器开发行业上来,他们或许觉得游戏服务器开发工资高,或许觉得做游戏服务器需要掌握的技术更高级,可以锻炼自己,或许觉得想换个环境等等。不管出于什么原因吧,做为一名几年的游戏服务器开发者,当然是持欢迎态度的,那么我就先介绍一下游戏服务器开发的工作吧,游戏服务器开发具体要做哪些工作呢?1,团队沟通基本上不管做什么开发,都是一个团队来完..._java游戏服务器开发用到数据库吗

PHP开发——Web的世界_php web开发-程序员宅基地

文章浏览阅读1k次,点赞2次,收藏10次。这篇关于PHP的文章主要介绍了PHP的特性以及其在Web开发、CMS系统、电子商务和数据库连结等应用场景。随着云平台、开发工具和移动应用程序等技术的不断发展,PHP将进一步提高其应用广度和深度。未来的PHP将支持更多的技术,并且将成为与Web开发工具、数据库技术、云平台、移动应用程序等相关的技术。此外,PHP未来的发展将更加高效和易用,使其更适合处理大量数据和请求,并充分考虑用户界面和易用性。_php web开发

windows启动tomcat闪退_tomcat windows闪退-程序员宅基地

文章浏览阅读1.2w次。现象:windows下双击tomcat\bin\startup.bat时闪退原因:缺少环境变量导致解决方法:打开编辑tomcat\bin\startup.bat,头部加入以下代码,一个是JAVA目录,一个是Tomcat目录SET JAVA_HOME=C:\Program Files\Java\jdk1.6.0_39SET TOMCAT_HOME=D:\hunk\work\apache-tomcat_tomcat windows闪退

数组内存存储_64位平台数组内存-程序员宅基地

文章浏览阅读201次。数组内存存储1. 基本类型数组的初始化2. 引用类型数组的初始化1. 基本类型数组的初始化 int[] array; array = new int[5]; for (int i = 0 ; i<array.length;i++){ array[i] = i + 1 ; } System.out.println(Arrays.toString(array));内存分析:2. 引用类型数组的初始化//定义Person类class Person{ private S_64位平台数组内存

Vue 食用指南-程序员宅基地

文章浏览阅读738次,点赞13次,收藏16次。本文记录了 Yukiii 学习 Vue 期间的心得和相关功能的具体实现及 Vue 的基本使用方法,方便后续开发时的查阅~

随便推点

使用python生成随机数(random模块)_random.random()产生的数-程序员宅基地

文章浏览阅读5.4k次,点赞2次,收藏17次。使用python生成随机数(random模块)_random.random()产生的数

软件测试全网最全复习总结-别杠,杠就是你对_软件规范化和标准化的原因不包括-程序员宅基地

文章浏览阅读1.1w次,点赞104次,收藏452次。今天仍然拼命看书,因为明天就要考了。学期的成绩就全仗这两天挣,现在更感到考试无用与无聊。——季羡林文章目录概述软件测试分类及流程黑盒测试等价类划分边界值分析法决策表法正交测试法极差法方差法白盒测试单元测试集成测试国际化和本地化测试可靠性测试测试与质量分析报告_软件规范化和标准化的原因不包括

iOS —— use_frameworks! 作用-程序员宅基地

文章浏览阅读1.3k次。通过cocoapods管理应用程序时,在Podfile文件中,**use_frameworks!*cocoapods会生成对应的 frameworks 文件 在Link Binary With Libraries:会生成Pods_工程名.framework,包含了其它用cocoapods导入的第三方框架的.framework文件1、纯OC项目中,通过cocoapods导入OC库时,一般都不使用use_frameworks!2、纯swift项目中,通过cocoapods导入swift库时,必须使用u..._use_frameworks!

Python菜鸟晋级04----raw_input() 与 input()的区别_pycharm没有raw input-程序员宅基地

文章浏览阅读2.5k次。raw_input() 与 input()均是python 的内建函数,通过读取控制台的输入与用户实现交互。但他们的功能不尽相同。举两个小例子>>> raw_input_A = raw_input("raw_input: ")raw_input: abc >>> input_A = input("Input: ")Input: abcTraceback (most recent ca_pycharm没有raw input

高通AR增强现实多卡识别和扩展跟踪Unity_imagetarget扩展追踪-程序员宅基地

文章浏览阅读1k次。只需修改ARcamera上的Max Simutaneous Tracked Images 的值就好了。初始是1,默认只能识别一张图。 扩展跟踪是一个更简单的事情,高通把这个功能封装成了ImageTarget的一个属性 Extended Tracking,只要将其勾上就可以了._imagetarget扩展追踪

对于三星手机的手工root方法-程序员宅基地

文章浏览阅读172次。现在很多一键化的root工具,但是仍然有不少的三星手机是无法用全自动方式进行root的,这时候,我们可以选择使用手工的方式进行root,本文章对手工root的一些方法进行一些介绍。   常规方法:..._三星手机用面具root

推荐文章

热门文章

相关标签