搜索算法
广度优先搜索(BFS)
查找某个值:用队列实现,从根结点开始,子结点从左到右依次入队,当前结点不是目标点,出队,子结点入队,继续搜索
查找到目标点的路径:采用open-close表,基于状态空间搜索,状态空间就是从原点到目标点搜索过程中,路线是曲折的,形成了一个图,这个图就是状态空间。求解路径实际是在这个图中搜索,也就是基于状态空间、基于图的搜索。
广度优先搜索可以保证得到最优解,最终结果是一颗解答树
辅助数组parent[i] 表示结点i的父结点,找到目标结点后,根据该数组向上查找父结点,可获取路径
一般步骤:1、初始结点的子结点依次入队,
2、队列出队
3、看当前结点是否能扩展,能则扩展一个结点,如果被访问过,则抛弃,扩展下一个结点。
4、检查结点是否是目标结点,是则搜索成功,不是,将其放入队列尾部,设置其父结点,返回第3步
单源最短路径Dijkstra 最短路径为v0...vk.vn
如果从v0到vn的距离是最短的,那么v0到vk也是最短的,
图G = (V,E) 集合S表示以确定最短路径的顶点集合,U表示未确定最短路径的顶点集合
辅助数组D[I]表示最短路径上结点I的前一个结点
1、选取与V0距离最小的顶点加入集合S,更新到所有顶点的最短距离,以新点为中间点,d[0][j] = min{d[0][i]+d[i][j],d[0][j]},如果进过i点距离变小,更新pre[j]=I
2、从集合U中选取v0可达的距离最短的点加入集合S,更新距离
for()初始化 isVisit pre[] G[I][J] dist[i]
for()每个顶点都要加入到集合S中
{
for()选取未访问且距离最短的点
for()以该点,为中间点,更新到所有顶点的距离,更新规则如1所示
}
2、深度优先搜索DFS
图的深度优先类似于树的先序遍历。同样使用一个辅助数组par[i]记录i点父结点
1、访问未被访问的点,标记已被访问
2、搜索该点的邻接点,未被访问,进行第一步,继续第二部;否则寻找下一个点
3、从初始点开始,for循环对它的,每一个子结点执行1、2的步骤
func() { for(当前点的每个子结点){ func() }
3、启发式搜索A*算法
前面的搜索都是盲目搜索,即毫无方向的搜索,启发式搜索可以保证一直向目标点移动
公式表示为f(n)=g(n)+h(n) f(n)表示经由结点N到目标点的估计距离,g(n)表示到N点的实际距离,h(n)表示从N点到目标点的估计距离
A*的搜索效率关键在于启发函数h(n)的选取,h(n)<=n到目标点实际值d(n),搜索范围大,搜索点数多,能得到最优解,但是效率较低
h(n)>n到目标点实际值d(n),搜索范围小,搜索点数少,不保证得到最优解,但是效率较高
创建2个表,OPEN表存放已生成但是未被考察的点,CLOSED表存放已被访问的点
首先把初始点放入OPEN表
while(OPEN表不空)
{ 从OPEN表取一个估价函数h(n)最小的点,因为每次选取的都是最小的点,也就是经过该点则离目标点的距离最小,不用考虑每个结点子结点是不是可以直接到,不用绕圈
if(n是目标点) 函数结束;
for(N的每个子结点C)
{ 计算C的估计值f(C)
if(C在OPEN表中)
{ 如果C的估计值比OPEN表里的小,更新C的父亲为N,更新C的估计值为F(C) }
if(C在CLOSED表中)
{ 执行下一次for体,continue}
if(C不在两个表中)
{ 设置C的父亲为N,计算h(C),把C放入OPEN表中}
}
把N结点插入CLOSED表,从OPEN表删除,按照估价函数值对OPEN表排序
}