当前位置:   article > 正文

A*搜索算法

a*搜索算法

目录

简述

算法流程

 算法实现与求解

求解过程

算法实现

数据结构

代码实现


简述

A搜索算法是一种启发式搜索的算法,通过估价函数f(x)=g(x)+h(x)对节点进行排序

g(x)为起点到该节点的到代价估计,h(x)为启发值(受对实际问题的理解而不同),为估计该节点到目标节点的代价估计

当g(x)与h(x)足够保守为最小代价估计,就变为了A*算法

算法流程

 算法实现与求解

求解过程

以下面的图为例,讲解一下具体过程

其中

括号内的数值为该节点到目标节点E的估计代价h

边上的数值为起点A到该节点的估计代价g

 首先从起点A出发,其代价估计值为

f(A)=g(A)+h(A)=0+20=20(自己到自己的代价为0)

nodeA/BCDE
f0

将A送入OPEN表里,OPEN表非空,将表里f最小的点进行后继节点BC拓展,同时移入CLOSED表

计算B,C的代价估计值

f(B)=g(AB)+h(B)=1+14=15

f(C)=g(AC)+h(C)=6+8=14

f(D)=g(AD)+h(D)=9+4=13

nodeA./B/AC/AD/AE
f0151413

此时OPEN表非空,将表里f最小的点D进行后继节点E拓展,同时将其移入CLOSED表

f(E)=g(ADE)=(9+20)+0=29

nodeA./B/AC/AD./AE/D
f015141329

此时OPEN表非空,将OPEN表里f最小的点C进行后继节点D拓展,同时将其移入CLOSED表

f(D)'=g(ACD)+h(D)=(6+1)+4=11<f(D)更新f(D)的取值

nodeA./B/AC./AD/CE/D
f015141129

此时OPEN表非空,将OPEN表里f最小的点D进行后继节点E拓展,同时将其移入CLOSED表

f(E)'=g(ACDE)+h(E)=(6+1+20)=27<f(E)更新f(E)

nodeA./B/AC./AD./CE/D
f015141127

此时OPEN表非空,将OPEN表里f最小的点B进行后继节点CD拓展,同时将其移入CLOSED表

f(C)'=g(ABC)+h(B)=(1+1)+8=10<14更新C

f(D)'=g(ABD)+h(D)=(1+4)+4=9<f(D)=11更新D

nodeA./B/AC/BD/BE/D
f01510927

此时OPEN表非空,将OPEN表里f最小的点D进行后继节点E拓展,同时将其移入CLOSED表

f(E)=f(ABDE)+h(E)=25

nodeA./B./AC/BD./BE/D
f01510927

此时OPEN表非空,将OPEN表里f最小的点C进行后继节点D拓展,同时将其移入CLOSED表

f(D)'=g(ABCD)+h(D)=(1+1+1)+4=7<9更新D

nodeA./B./AC./BD/CE/D
f01510927

此时OPEN表非空,将OPEN表里f最小的点D进行后继节点E拓展,同时将其移入CLOSED表

f(E)'=g(ABCDE)+h(E)=(1+1+1+1+20)+0=23<27,更新E

nodeA./B./AC./BD./CE/D
f01510923

此时OPEN表非空,将OPEN表里f最小的点E移入CLOSED表

nodeA./B./AC./BD./CE./D
f01510923

此时OPEN表为空算法结束

路径为A->B->C->D->E,代价为23

算法实现

分为数据结构以及功能类的编写,要实现这个算法就要实现

数据结构

  1. class node():
  2. def __init__(self,node:int,parent:int,g,h):
  3. '''node等于parent时说明该节点为起点\n
  4. node:节点序号\n
  5. parent:父亲节点\n
  6. g:路径代价\n
  7. h:启发式信息,该点到终点希望更大h越小'''
  8. self.node=node
  9. self.parent=parent
  10. if node==parent:self.g=0
  11. else:self.g=g
  12. self.h=h
  13. self.f=g+h

代码实现

  1. import os
  2. nodenum=26
  3. #0号下标不用,下方的测试数据也是
  4. letter=['']+[chr(ord('A')+i)for i in range(nodenum-1)]
  5. class node():
  6. def __init__(self,node:int,parent:int,g,h):
  7. '''node等于parent时说明该节点为起点\nnode:节点序号\nparent:父亲节点\ng:起点到目标节点代价\nh:终点到目标节点代价'''
  8. self.node=node
  9. self.parent=parent
  10. if node==parent:self.g=0
  11. else:self.g=g
  12. self.h=h
  13. self.f=g+h
  14. def sortkey(nodes:node):
  15. '''将node节点的f(n)作为sort排序函数比较点key,返回节点的f(n)'''
  16. return nodes.f
  17. class AS():
  18. '''data格式如(1,0,3),(0,2,5)表示为[[[2,5]],[[0,3]],[]]'''
  19. def __init__(self,data:list,hlist,target,o):
  20. '''data:数据集合\nhlist:节点启发式信息集合\ntarget:终点\no:起点'''
  21. #OPEN,CLOSED表初始化
  22. self.OPEN:list[node]=[]
  23. self.CLOSED:list[node]=[]
  24. self.data=data
  25. self.hlist=hlist
  26. self.target=target
  27. self.o=o
  28. def findnodC(self,nod):
  29. '''CLOSED表中查找有无节点nod\n有返回节点在CLOSED表中的下标,否则返回-1'''
  30. for i in range(len(self.CLOSED)):
  31. if self.CLOSED[i].node==nod:
  32. return i
  33. return -1
  34. def findnodO(self,nodei:node):
  35. '''OPEN表中查找有无节点nodei,如果有则比较nodei的f(n)与表中节点的f(n)谁小,保留小的那个\n若没有,则直接添加'''
  36. x=-1
  37. #查找OPEN表有无nodei节点名相同的点
  38. for i in range(len(self.OPEN)):
  39. if self.OPEN[i].node==nodei.node:
  40. x=i
  41. break
  42. if x==-1:
  43. #OPEN表中没有nodei.node节点
  44. self.OPEN.append(nodei)
  45. else:
  46. #OPEN表中有nodei.node节点,比较这两个节点的f(n)值
  47. if self.OPEN[x].f>nodei.f:
  48. del self.OPEN[x]
  49. self.OPEN.append(nodei)
  50. def findmin(self):
  51. '''返回OPEN表中f(n)最小的节点'''
  52. #由于OPEN经过重排,-1下标的节点f(n)最小
  53. minnode=node(self.OPEN[-1].node,self.OPEN[-1].parent,self.OPEN[-1].g,self.OPEN[-1].h)
  54. #查看CLOSED表中有没有这个节点
  55. x:int=self.findnodC(minnode.node)
  56. if x==-1:
  57. #CLOSED表,没有则添加
  58. self.CLOSED.append(minnode)
  59. else:
  60. #CLOSED有,则比较f(n)值
  61. if self.CLOSED[x].f>minnode.f:
  62. del self.CLOSED[x]
  63. self.CLOSED.append(minnode)
  64. del self.OPEN[-1]
  65. return minnode.node
  66. def sortOPEN(self):
  67. '''重排OPEN表'''
  68. def sortkey(nodes:node):return nodes.f
  69. #''重排OPEN表'''
  70. self.OPEN.sort(key=sortkey)
  71. self.OPEN=self.OPEN[::-1]
  72. def Tuozhang_Sort(self,n):
  73. '''拓展OPEN表中的节点n,将其移入CLOSED并重排OPEN表'''
  74. #当节点没有后继节点,return空
  75. length=len(self.data[n])
  76. if length==0:return
  77. #当节点有后继节点
  78. for m in range(length):
  79. i=self.data[n][m]
  80. nod=i[0]
  81. #后继节点g(n)=父亲节点的g(n)值加上两点间的权重
  82. g=self.CLOSED[-1].g+i[1]
  83. #启发式信息
  84. h=self.hlist[nod]
  85. #查找OPEN表中有无此节点,如果有则比较nodei的f(n)与表中节点的f(n)谁小,保留小的那个\n若没有,则直接添加
  86. self.findnodO(node(nod,n,g,h))
  87. self.sortOPEN()
  88. def findparent(self,nod):
  89. '''返回nod节点的父亲节点,如果没有则返回-1'''
  90. for i in self.CLOSED:
  91. if i.node==nod:
  92. #当找到起点(parent=node)则停止
  93. if i.parent==nod:
  94. return -1
  95. return i.parent
  96. return -1
  97. def AS(self):
  98. '''返回代价以及路径'''
  99. #按算法流程实现
  100. #首先初始化S
  101. S=node(node=self.o,parent=self.o,g=0,h=self.hlist[self.o])
  102. #将S放入OPEN表
  103. self.OPEN.append(S)
  104. while True:
  105. #如果OPEN表为空则失败
  106. if len(self.OPEN)==0:break
  107. #查找OPEN表中最小f(n)的节点
  108. i=self.findmin()
  109. #如果i是目标则停止
  110. if i==self.target:break
  111. #拓展OPEN表中的节点i,将其移入CLOSED并重排OPEN表
  112. self.Tuozhang_Sort(i)
  113. #显示模块,在下一行的'''前加#即可
  114. '''
  115. print('##############\nClosed')
  116. for i in self.CLOSED:
  117. print('({},{})'.format(l[i.node],i.f))
  118. print('##############\nOpen')
  119. for i in self.OPEN:
  120. print('({},{})'.format(l[i.node],i.f))
  121. input('回车继续')
  122. os.system('clear')
  123. #'''
  124. #self.CLOSED[-1]为目标节点
  125. cost=self.CLOSED[-1].g
  126. path0=[]
  127. #逆推通过parent找到路径
  128. while 1:
  129. path0.append(i)
  130. i=self.findparent(i)
  131. if i==-1:break
  132. #由于一直往后插入节点,因此需要一次翻转
  133. path0=path0[::-1]
  134. #将节点转化为用字母表示
  135. path=''
  136. for i in path0:
  137. path+=(letter[i]+'->')
  138. path=path[:-2]
  139. return cost,path
  140. '''测试数据1
  141. initnode=1
  142. endnode=5
  143. datas=[ [],
  144. [[2,1],[3,6],[4,9]],
  145. [[3,1],[4,4]],
  146. [[4,1]],
  147. [[5,20]],
  148. []]
  149. h=[0,20,14,8,4,0]
  150. #'''
  151. #'''测试数据2
  152. datas=[
  153. [],
  154. [[2,2]],
  155. [],
  156. [[1,1],[4,2]],
  157. [],
  158. [[1,4],[3,1]],
  159. [[7,1]],
  160. [[8,2],[5,1]],
  161. []
  162. ]
  163. initnode=6
  164. endnode=2
  165. # [0,1,2,3,4,5,6,7,8]
  166. # [0,a,b,c,d,e,f,g,h]
  167. h=[0,2,0,3,3,4,6,5,3]
  168. #'''
  169. solution=AS(datas,h,target=endnode,o=initnode)
  170. cost,path=solution.AS()
  171. print('##############\nClosed\n--------------')
  172. for i in solution.CLOSED:
  173. print('({},{})'.format(letter[i.node],i.f))
  174. print('##############\nOpen \n--------------')
  175. for i in solution.OPEN:
  176. print('({},{})'.format(letter[i.node],i.f))
  177. print('##############')
  178. print('cost:',cost)
  179. print('path:',path)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/558839
推荐阅读
相关标签
  

闽ICP备14008679号