这个算法不是最短路算法,只是一个基本的搜索算法,但是可以得出图中是否能找到指定节点
从起始节点开始,将其标记为已访问。
检查当前节点的相邻节点中是否存在未访问的节点。
若存在未访问的节点,则选择其中一个未访问节点作为下一个当前节点,并将其标记为已访问。然后回到步骤 2。
若不存在未访问的节点,则回溯到上一个节点,即回到该节点的上一级节点,并重复步骤 2。
重复步骤 4,直到所有节点都被访问。
存在一个全局变量存储一个二维数组或邻接表,描述整张图
建立一个函数dfs,参数标记当前节点在图中的位置,以及目标节点的特征或位置,返回值可以为是否找到
进入函数,先将当前节点设为已访问
如果当前节点是目标,直接返回真
按照一定顺序读取周围可以到达的未访问过的节点,递归调用dfs函数,如果dfs返回真,则函数立即返回真,如果dfs返回伪,继续寻找周围可走的节点
如果周围的节点都不能走,即函数执行到了这一里,则返回伪
虽然一般都是先学dfs再学bfs,但是我认为,bfs比dfs简单
从起始节点开始,将其标记为已访问,并将其加入队列。
从队列中取出一个节点作为当前节点。
判断这个节点是否为终点,如果是,循环的次数就是最短路径长,且可以
检查当前节点的所有相邻节点中是否存在未访问的节点。
若存在未访问的节点,则将其标记为已访问,并将其加入队列。
重复步骤 2-5,直到队列为空。
它的实现差不多是这样,
现在我们看一个早期的启发式搜索,它在图寻路中引用场景最广因为它考虑到边权,但是,边权为0时,它会退化为广度优先搜索
初始化:将起始节点标记为已访问,距离起始节点的距离设置为0,并将所有其他节点的距离设置为无穷大。
找到最短路径:从起始节点开始,按照当前已知的最短距离,在未访问的节点中选择一个距离最小的节点进行访问。
更新节点距离:对于所选的节点,计算该节点与其相邻节点的距离和。如果通过当前节点到达相邻节点的距离比之前记录的最短距离要小,则更新最短距离。
标记已访问:标记当前节点为已访问,意味着已找到从起始节点到该节点的最短路径。
重复步骤2-4:重复执行步骤2到4,直到所有节点都被标记为已访问或者没有可访问的节点为止。这样,每个节点的最短路径就都得到了确定。
输出最短路径:最后,根据计算得到的最短路径信息,可以输出从起始节点到每个节点的具体路径
实现也差不多,现在不方便贴代码,只能讲讲思路,一般实现是架邻接表而不是二维数组,因为二维数组不方便描绘边权
思路最简单的算法Floyd思路是:
初始化:创建一个二维数组D,用于保存节点之间的最短路径距离。初始时,如果两点之间存在边,则将其距离赋值给D;如果两点之间没有边,则将其距离设为无穷大。
迭代更新:对于每个顶点k,以顺序的方式遍历每对节点i和j,尝试通过节点k来改进节点i和节点j之间的最短路径。即,如果节点i到节点j的距离大于节点i到节点k的距离加上节点k到节点j的距离(即D[i][k] + D[k][j]),则更新节点i到节点j的距离为D[i][k] + D[k][j]。
重复迭代:继续进行迭代更新,每次都考虑一个新的中间节点k,直到所有节点都被作为中间节点考虑过一次。
输出最短路径:迭代完成后,二维数组D中保存的即为任意两点之间的最短路径距离。
但是,它的时间复杂度是难以接受的,高达O(n^3)
它在每一步选择时都采取当前看起来最好的选择,并希望通过一系列局部最优的选择来达到全局最优,且不会回头。
贪心搜索的基本思想如下:
初始化:确定问题的初始状态。
选择阶段:从当前状态开始,根据某个标准选择一个最好的操作或决策。这个选择是基于局部信息的,它不会考虑之前的选择或者未来的结果。
更新状态:根据所选择的操作或决策,更新当前状态。
终止条件:如果当前状态满足终止条件(到达终点),则结束搜索;否则返回第2步。
具体实现依赖于一个启发函数,用于检测周围哪个点里终点更近
贪心算法的目光是短浅的,所以得到的结果不一定正确,但是它通常执行速度较快。因此,在某些情况下,贪心搜索可能会得到次优解或者无法找到任何解。所以贪心这个算法是不合适的
最佳优先搜索(Best-First Search)是一种启发式搜索算法,它根据一个评估函数来选择下一个扩展的节点。评估函数用于估计当前节点到目标节点的代价或距离,算法总是选择具有最低评估值的节点进行扩展。
初始化:确定问题的初始状态。
维护一个待扩展节点的优先队列,初始时将初始状态放入队列中。
重复执行以下步骤直到找到解决方案或队列为空:
a. 从队列中取出评估值最低的节点。
b. 检查当前节点是否为目标节点,如果是,则找到了解决方案,结束搜索。
c. 否则,根据当前节点扩展出所有可能的子节点,并计算每个子节点的评估值。
d. 将子节点按照评估值由低到高的顺序插入队列中。
最佳优先搜索使用评估函数来选择下一个扩展的节点,根据评估值的大小进行排序。这种排序策略使得搜索算法更有可能朝着接近目标的方向前进,从而提高搜索效率。然而,最佳优先搜索并不能保证找到全局最优解,因为它只关注当前最佳的节点,并没有考虑之前的选择或未来的结果,但是最佳优先算法的比贪婪搜索更容易得到最优解,它有时会考虑回溯,但是依旧不保证最优解
A*(A-Star)是一种综合了最佳优先搜索和Dijkstra算法的启发式搜索算法。它在搜索过程中维护了两个值:一个是从起始节点到当前节点的实际代价(g值),另一个是从当前节点到目标节点的估计代价(h值)。
初始化:确定问题的初始状态,将起始节点放入开放列表。
维护两个列表:开放列表:存储待扩展的节点,按照f值(f = g + h)进行排序。 关闭列表:存储已经扩展过的节点。
重复执行以下步骤直到找到解决方案或开放列表为空:
a. 从开放列表中选择f值最小的节点作为当前节点。
b. 检查当前节点是否为目标节点,如果是,则找到了解决方案,结束搜索。
c. 否则,将当前节点从开放列表移动到关闭列表。
d. 根据当前节点扩展出所有可能的子节点,并计算每个子节点的g值和h值。
e. 对于每个子节点,如果它已经在开放列表或关闭列表中,比较新的g值与已有的g值,选择较小的更新;否则,将子节点加入开放列表。
A算法使用了启发式估计函数来指导搜索过程,它综合了实际代价和估计代价。g值表示从起始节点到当前节点的实际代价(通过已经扩展的路径),h值是从当前节点到目标节点的估计代价,通常使用启发式函数(如曼哈顿距离或欧几里得距离)来计算。A算法选择f值最小的节点进行扩展,f值较小的节点具有更高的优先级。
A算法在满足一定条件下能够保证找到最短路径(最佳解决方案),即f值最小的节点是全局最优解。然而,在某些情况下,A算法可能会受到启发式函数的影响而无法找到最佳解决方案,或者搜索空间非常庞大时会消耗大量的时间和内存。
接下来对A*进行一些优化
在A*算法中,h值是通过启发式函数进行估计的,这个估计值对搜索的效率和质量影响很大。然而,有些情况下,启发式函数可能无法提供准确的估计。例如,在某些问题中,启发式函数可能无法获得目标节点的准确估计代价,导致搜索算法受到偏差而无法找到最优解。
B算法引入了一个新的概念——子目标(subgoal),并采用了更加灵活的估计方式。B算法中,该算法会先生成一个子目标,然后通过子目标来修正启发式函数的估计值。具体步骤如下:
初始化:确定问题的初始状态,将起始节点放入开放列表。
维护两个列表:开放列表:存储待扩展的节点,按照f值(f = g + h)进行排序。 关闭列表:存储已经扩展过的节点。
重复执行以下步骤直到找到解决方案或开放列表为空: a. 从开放列表中选择f值最小的节点作为当前节点。 b. 检查当前节点是否为目标节点,如果是,则找到了解决方案,结束搜索。 c. 否则,将当前节点从开放列表移动到关闭列表。 d. 根据当前节点扩展出所有可能的子节点,并计算每个子节点的g值和h值。 e. 对于每个子节点,根据子目标修正启发式函数的估计值,并计算新的f值。 f. 将子节点加入开放列表。
B算法通过不断调整启发式函数的估计值来获取更准确的路径估计。它使用子目标来指导搜索过程,根据子目标的信息修正启发式函数的估计值,并根据新的估计值进行节点扩展。这个过程允许B算法在搜索过程中逐渐修正路径的估计,并更好地适应问题的特点。
D*(D-Star)是一种基于改变图搜索和路径规划的增量式算法。它用于在已知环境地图上进行路径规划,并能够在地图信息发生变化时进行快速更新。
初始化:确定问题的初始状态,包括起始节点和目标节点,并初始化其他相关数据结构。
维护两个主要数据结构:状态图(State Graph):记录了每个节点的状态、代价、连接关系等信息。 优先级队列(Priority Queue):按照代价进行排序的队列,用于选择下一个扩展的节点。
重复执行以下步骤直到找到解决方案或无法找到路径: a. 从优先级队列中选择代价最小的节点作为当前节点。 b. 检查当前节点是否发生了变化(例如,代价更新或连接关系改变),如果是,则更新相关信息。 c. 更新与当前节点相邻的节点的代价,并计算新的代价值。 d. 如果目标节点的代价发生了变化,则重新评估路径。否则,沿最佳路径进行扩展。 e. 根据更新的信息,重新排序优先级队列。
D算法通过不断更新节点的代价和连接关系来适应地图变化,并动态调整路径规划过程。它使用增量式的搜索和更新策略,可以在修改地图或代价信息后,快速重新规划路径。D算法重复进行节点的选择和扩展,直到达到目标节点或无法找到路径。
起点和终点对换一下,再执行算法就是逆向,然而,这没太大的优化作用,接下来结合正向和逆向
的思路,将正向的搜索结果放入一个数组,逆向的放入另一个,直到两个数组出现重叠,说明找到,这样可以有效的缩减搜索范围实现优化