A*搜寻算法的高效之处
在最短路径搜寻效率上,一般有A*>Dijkstra、双向BFS。
A*算法最为核心的过程,就在每次选择下一个当前搜索点时,是从所有已探知的但未搜索过点中(可能不同层,也可能不在同一支路),选取f值最小的节点进行展开。
所有“已探知但未搜索点”可以通过一个按f值升序的队列(优先队列)进行排列。
OPEN表表示已经展开但还没有访问的节点集,另一个CLOSE表表示那些已经访问过的节点集。
蛮力搜索(BFS,DFS)
BFS(宽度优先搜索,Breadth-First-Search)
首先将起始点放入OPEN表,CLOSE为空:
1、如果OPEN不为空,从中取节点S,为空算法失败;
2、S是目标解吗?是,找到一个解(继续或终止);不是转3;
3、将所有S的所有后继节点展开,就是从S可以直接关联的节点,若不在CLOSE中,就将其放入OPEN表尾,S放入CLOSE表,重复1。
DFS(深度优先搜索,Depth-First-Search)
1、如果OPEn不空,从中取S,空,算法失败;
2、S是目标解码?是,找到一个解(继续或终止);不是转3;
3、将S的所有后继展开,就是从S可以直接关联的节点,若不在CLOSE中,就将其放入OPEN开始,S放入CLOSE表,重复1。
观察OPEN表中的访问节点组织形式,BFS是从表头取节点,从表尾添加节点,也就是说OPEN是一个队列;
DFS从OPEN表头取节点,也从表头添加节点,OPEN为一个栈。
注意:DFS用到了栈,可以使用递归实现,好处是在系统中只需要存节点最大深度那么大的空间。
利用系统栈实现DFS
函数dfs(节点 s)
{
s超过最大深度了吗?是:相应处理,返回;
s是目标节点吗?是:相应处理;否则;
{
s放入CLOSE表;
for(c=s.第一个节点;c不为空;c=c.下一个节点())
if(c不在CLOSE表中)
dfs(c):递归
}
}
在象棋等棋类程序中,就是用DFS基本模式搜索棋局局面树的。
启发式搜索:
为了改善上面的算法,我们需要对展开后续节点时对子节点有所了解,需要估值函数,用来评价子节点的好坏。
排序可能是对OPEN表整体进行排序,也可以是对后续展开的子节点排序,排序的目的就是要使程序有启发性,更快搜出目标解。
如果估值函数只考虑节点的某种性能上的价值,而不考虑深度,有序搜索(Ordered-Search),着重看好能否找出解,而不看解离起始节点的距离(深度)。
如果估值函数考虑了深度,或者是带权距离(从起始点到目标节点的距离加权和),就是A*。
A*就是将估值函数分成两个部分,一个是路径价值,另一个就是一般启发性价值。