从DFS到WeightedA*--图搜索算法的前世今生

 

 

一. 图的基础

     (1)   图的结构: 

                   

     (2)   图的要素:

                      图 =   顶点(vertex)  + 边(edge)  +    权重(weight)  +  度 (degree)

                     G(V, E, W, D)    

 

  •    度:与这个顶点相连接的边的数目。
  •   入度:有向图中,指向该顶点的边。
  •   出度:有向图中,从该顶点出发,指向其他顶点的边。                                  

     (3)  图的分类:

         有向无向

           有权无权

            

 

                                     

 (4) 图的表示:           

           4.1  图的表示方法一:邻接表

    

        

        引申:

                         

             应用:?

 

   4.2  图的表示方法二:邻接矩阵

             

 

 

           4.3  图的稠密稀疏判定

            

                                     

表示方法空间、时间复杂度是否能表示方向能否直接表示权重选取原则一般性原则稀疏稠密判定
邻接表O(V+E)不能直接表示,改动后可以适合表示稀疏图同一个节点的边的个数小于10.均使用邻接表处理。! ( V << E )
邻接矩阵O(V^2)适合表示稠密图

V << E

接近完全图

【例1】图的表示方法实例:

GraphtestG.txt

 

 

 

邻接表邻接矩阵

 

 

 

 

 

 

 

 

二. 图搜索基础:

     2.1   深度优先搜索(DFS) 

(1)DFS过程

012

 

 

 

 

 

345

 

 

 

 

 

6

7

8

 

 

 

 

 

910 

 

 

 

 

 

 


(2) DFS代码:

class Component{

private:
    Graph &G;        //图的引用
    bool *visited;   //标记顶点是否被访问
   
    void dfs( int v ){

        visited[v] = true;
        typename Graph::adjIterator adj(G, v);
        for( int i = adj.begin() ; !adj.end() ; i = adj.next() ){
            if( !visited[i] )
                dfs(i);
        }
    }
}


【例2】DFS应用实例  

2.2  广度优先搜索(BFS)----无权图单源最短路径问题

(1)BFS过程:

012

345

678

910 

BFS输出了无权图的从起点到任意点的最短路径。


(2)BFS代码:

 void bfs(Graph &graph, int s){
    queue<int> q;         //
    q.push( s );   
    visited[s] = true;    //标记是否被访问过,只要加入队列,就标记为访问过
    while( !q.empty() ){

        int v = q.front();
        q.pop();
        typename Graph::adjIterator adj(G, v);
        for( int i = adj.begin() ; !adj.end() ; i = adj.next() ){
            if( !visited[i] ){
                q.push(i);
                visited[i] = true;
            }
        }
    }

}

【例3】BFS应用实例----无权图最短路径算法

 

局限性:不能处理带权图         

2.3 图搜索算法基本框架      

/***********************************************************************************************************

      1 维持一个容器,该容器中存放需要访问的顶点;

      2. 首先用起始顶点Xs来初始化该容器;

      3. LOOP:

                  3.1  依据预先设定好的Score Function,从容器中弹出一个顶点;     (Remove)

                  3.2   根据该顶点,去拓展它的邻居;                                              (Expansion)

                  3.3   将该顶点的邻居装进容器中;                                                  (Push)

       4. END LOOP;

 *************************************************************************/

【总结与反思】

           DFS : 维护一个stack,优先弹出最先进入的顶点;

           BFS : 维护一个queue,优先弹出层级最浅的顶点,但是只能用于求无权图的最短路径算法;


三.图搜索算法进阶:
 

      与无权图相比,带权图的最短路径与顶点个数无关,与权值之和相关:

  2.1 Dijkstra:----带权图单源最短路径问题----路径规划问题

 

(1)算法过程:

012

345

678

(2)算法伪代码

/***********************************************************************************************************

      1 维持一个优先级队列用来存放将要扩展的顶点;

      2. 首先用起始顶点Xs来初始化该容器;

      3.假设  g(Xs) = 0   and   g(n) = 无穷大

      4. LOOP:

                  4.1  if priority queue is empty

                              return false

                             break

                  4.2   remove mode "n" with the lowest g(n) from the priority queue        ( Remove )

                  4.3  if the node "n" is the goal

                               return true

                               break

                  4.4   for all unexpanded nerghbors "m" of "n"                                          ( Expansion )

                                   if  g(m) = 无穷大;

                                                g(m) = g(n) + Cnm;

                                                push m into the queue;                                                   ( Push )

                                  if g(m) > g(n) + Cnm;

                                               g(m)=g(n) + Cnm;

                 4.5    end

       5. END LOOP;

 *************************************************************************/

【例4】Dijkstra应用实例 

【总结与反思】

 

        Dijkstra 算法可以求解带权图的最短路径,但是该算法没有方向性,从起点开始,一层一层,向外盲目穷举,直到到达终点为止或者遍历结束为止。

如何引入方向性?---- 启发式搜索方式 

       2.2  贪心搜索算法:

        heuristic:指的是人为定义的一种启发式策略,在下图中,我们可以定义当前节点距离与终点的欧氏距离或者曼哈顿距离为启发函数,每次弹出距离终点最短的节点,以该策略作为拓展节点的规则,如下所示:

在无障碍的环境下的效果演示:

 

 

在有障碍物的地图下的效果演示:

 

 

【总结与反思】

算法优点缺点
BFS

无权图最短路径

全局最优

无方向性,层序扩展
Dijkstra

有权图最短路径

全局最优

无方向性,层序扩展
geedy best search有方向性容易陷入局部最优

 

 

能否将二者进行结合?


  2.3  A star算法:

(1)  算法思路:

        

                                 

 

 

                              A star =  Dijkstra + Heuristic

 

  • 维护一个从起点到当前节点的cost的累计情况:g(n)
     
  • 通过启发函数,维护一个从当前节点到终点的估计值:h(n)
     
  • 计算 f(n)   =   g(n)   +   h(n), 以f(n)的大小作为优先级队列的排序依据
     
  • 从容器中弹出节点时,每次弹出f(n)最小的节点
     

(2)算法伪代码:

/***********************************************************************************************************

      1 维持一个优先级队列用来存放将要扩展的顶点;

      2.  启发式函数,h(n)的计算方式是预先设定好的

      3. 首先用起始顶点Xs来初始化该容器;

      4.假设  g(Xs) = 0   and   g(n) = 无穷大

      5. LOOP:

                  5.1  if priority queue is empty

                              return false

                             break

                  5.2   remove mode "n" with the lowest f(n) =  g(n)  +  h(n) from the priority queue        ( Remove )

                  5.3  if the node "n" is the goal

                               return true

                               break

                  5.4   for all unexpanded nerghbors "m" of "n"                                          ( Expansion )

                                   if  g(m) = 无穷大;

                                                g(m) = g(n) + Cnm;

                                                push m into the queue;                                                   ( Push )

                                  if g(m) > g(n) + Cnm;

                                               g(m)=g(n) + Cnm;

                 5.5    end

       6. END LOOP;

 *************************************************************************/

(3)算法的最优性保证

反例:

 

如图:

     f(G)  = 5+0 = 5

     f(A)  = 1+6  = 7

 

虽然实际花费 S→ A → G  < S → G  但是由于启发函数设计不合理  ,算法仍然选择了下面这条路。

 

最优性保证:  启发函数估计的 h(n)  必须小于实际花费 h*(n)

                            h(n)  <  h*(n)  

                       

 

 

上图的 情形,下面的几种   h(n)  是否满足最优性:

     1  欧式距离

     2  曼哈顿距离

     3  无穷范数

     4  0

【总结与反思】

(1)

        最优?  最快?

如果算法稍微丧失最优性,但是速度却可以获得几十倍的提升的话,我们需要在最优与最快之间做权衡:

 

WeightedA*      f(n) = g(n) +  alpha * h(n)       (最优性换取速度)

   

     alpha  =  0              Dijkstra

      alpha =  1              A*

      alpha = 无穷         贪心算法

 

特点:

  1) 最优性换取速度

  2) 花费大于最优情况下的花费

  3) 速度比A×快

 

 

 

公式

f (n) = a*g(n) + b*h(n)

 
效果

 

 
a0111 
b11>10 
算法GreedyA*WeightA*Dijkstra 

 

下面的链接中可以设置参数观看各种算法的情况

http://qiao.github.io/PathFinding.js/visual/  

 

(2)最优启发式函数的选取

        闭式解直接求最优h*(n)的条件:  

        结构化地图+固定移动方式

          

  上图 h*(n) 可以直接求得。

 

  2.4  拓展

  • WeightA*
  • JPS算法

  • D*

 

参考文献

【1】https://www.cnblogs.com/xuuold/p/10366834.html

【2】https://www.zhihu.com/search?type=content&q=Astar%E7%AE%97%E6%B3%95

【3】https://www.zhihu.com/search?q=%EF%BC%A1star%E7%AE%97%E6%B3%95&utm_content=search_history&type=content

【4】深蓝学院《移动机器人路径规划》

【5】liuyunbobobo老师《算法与数据结构》

【6】http://qiao.github.io/PathFinding.js/visual/  

 

 

 

 

 

 

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值