A*算法的目的是找到一条从起始状态到最终状态的最短路径。算法
在A*算法中,须要在每一个点计算启发函数:f(S) = g(S) + h(S),其中g(S)是从起点到S点的距离,h(S)是对从S点到终点的最短距离的估计值。数据结构
若是把g(S)看成深度,又令h(S) = 0,则A*算法就变成了BFS。函数
A*算法对BFS的改进在于把BFS所用到的队列改为按启发函数值排列的优先队列。spa
假设从状态S抵达终点的最短距离为H(S),那么启发函数中的h(S)必须知足h(S)<= H(S)。在此基础上,h和实际的距离越接近,须要计算的节点就越少,效果就越好。若是h(S) = 0,此时A*算法就变成了BFS,效果最差。设计
在解8数字谜题时,若是按照BFS的思路,咱们每次扩展四个节点,分别是空格上移、下移、左移和右移(固然,大多数节点是没法彻底扩展这四个方向的),一层层搜索以后,若发现了目标状态,则从目标状态节点开始向父节点回溯,由此就能够获得一个步数最少的解法了。可是BFS是盲目的,所以在搜索过程当中它搜索了不少“意义不大”的节点。因而咱们开始设计一个加入了必定启发信息的A*算法(其思路相似于分支限界),代码以下(参见P223 2.5.4.6小节):blog
A*() { // open表,用优先队列实现,用来保存待扩展的节点(改进自BFS中的队列)。 PriorityQueue open; // closed表,用HASH表或者其余可以高效检索的数据结构实现,用来保存已经扩展过的节点(能够考察一个状态是否已经被产生过)。 SymbolTable closed; open.Add(起始节点); while(!PriorityQueueEmpty(open)) { // 从open表中弹出一个最优的待扩展节点 S = PriorityQueueDeleteMax(open)); closed.Insert(S); // 若是S就是目标状态则结束 if(S == GOAL) { return OVER; } // 尝试扩展S的全部子节点 while(childS = S.nextChild()) { // 若是当前节点还没有被产生过 if(!closed.isInclude(childS)) { // 则将这个节点添加到open表中 PriorityQueueInsert(open,childS); } } } }