60-BFS的应用——求最短路径

1. 求最短路径

  这几篇将主要根据我们之前所学的图的遍历算法来解决一些问题,下面我们来看这样的一个问题。

  问题:求不带权连通图G中从顶点u到顶点v的一条最短路径。(即求顶点u到顶点v之间边数最少的顶点序列)。

60-BFS的应用——求最短路径_第1张图片
图1-求最短路径

  例如,对于这样的一个有向图,我们要求顶点0到顶点7的最短路径。对于求最短路径,我们是选择DFS还是BFS呢?这是一个值得思考的问题。

2. DFS or BFS



首先来看DFS深度优先搜索:

60-BFS的应用——求最短路径_第2张图片
图2-DFS深度优先搜索

  如果采用DFS深度优先搜索的话,得到的路径可能是0 - 1 - 3 - 6 - 7这样的路径,而根据之前我们学习DFS深度优先搜索过程可知,简单来说,DFS深度优先搜索就是选择一个方向(顶点),然后依次访问下去(访问邻接点),直到访问到终点为止,在这个过程中DFS深度优先搜索并不关心这是否是一条最短路径,而从最终搜索到的路径来看,这显然不是一条最短路径。



我们再来看BFS广度优先搜索:

60-BFS的应用——求最短路径_第3张图片
图3-BFS广度优先搜索

  从图3来看,BFS广度优先搜索是对每一层的所有相邻的顶点进行搜索,直到找到终点为止。在这个搜索过程中,广度优先搜索会对所有的邻接点进行了访问,因此当广度优先搜索完成后,我们就可以知道有这样的一条最短路径可以到达顶点v(即序列:0 - 2 - 5 - 7)。

3. 广度优先搜索算法思路

  1. 从顶点u出发一层一层地向外扩展

  2. 利用队列记录访问的顺序

  3. 当第一次找到顶点v时队列中便包含了最短路径,同时在搜索过程中利用队列存储最短路径(这是一个普通队列,而非之前所说的环形队列)

  4. 然后再利用队列输出最短路径(逆路径)


如果你还是有些疑惑的话(比如逆路径),不要急,接下来我们还会继续介绍。

4. 求最短逆路径算法

  最好是先把BFS算法先熟悉一下,有助于理解这个求最短逆路径算法,求最短逆路径算法的实现:

//求最短逆路径算法
void ShortPath(ALGraph *G,int u,int v)
{
    ArcNode *p;
    int w,i;
    struct QUERE qu[MAXV];
    //int front;
    //int rear;
    //设置visited数组
    int visited[MAXV];
    for(i=0; in; i++)
        visited[i]=0;

    //对起始点标记为已访问
    visited[u]=1;
    //设置队列
    int front = -1;
    int rear = -1;
    rear++;
    //将起始点入队,前驱设置为-1
    qu[rear].data=u;
    qu[rear].parent=-1;


    while (front!=rear) //队不空循环
    {
        //出队顶点w
        front++;
        w=qu[front].data;

        //然后判断是否为要找的终点
        //知道出队顶点w为7的时候,就可以输出路径了
        if (w==v)
        {
            //找到v时输出路径之逆并退出
            /*
                注意:因为这条路径是逆路径,所以要从顶点7开始输出,
                每次输出完后,开始找parent,根据parent找到上一个顶点的下标位置并输出
                ,以此类推,直到找到parent为-1则说明逆路径输出完毕
            */
            i=front;
            while (qu[i].parent!=-1)
            {
                printf("%2d ",qu[i].data);
                i=qu[i].parent;
            }
            printf("%2d\n",qu[i].data);
            break;
        }

        //访问w的所有邻接点(这一步操作非常重要,体现BFS广度优先搜索,相信大家对这一步操作已经不陌生了吧)
        p=G->adjlist[w].firstarc;
        while (p!=NULL)
        {
            if (visited[p->adjvex]==0)
            {
                visited[p->adjvex]=1;
                rear++;
                qu[rear].data=p->adjvex;
                qu[rear].parent=front;
            }
            p=p->nextarc;
        }
    }
}

5. 求最短路径算法的过程

60-BFS的应用——求最短路径_第4张图片
图4-求最短路径算法的过程

  还记得前面我们说过的逆路径吗?求最短逆路径算法过程如图4所示,BFS广度优先搜索会将所有搜索到的顶点进行入队,每个顶点入队时会记录两项信息,其中data域记录顶点的信息,parent域记录上一个顶点的下标位置。比如对于顶点5来说,data会记录顶点5的值,而parent域会记录顶点5的上一个顶点2的下标位置(下标为2)。这样我们就可以通过这种方式输出逆路径了。

  而求最短逆路径算法中的顶点w则会记录每个出队的顶点,所以当顶点w为顶点7时,此时顶点w和顶点v相等,则说明找到了最短逆路径,所以会从顶点7开始输出,并根据顶点7的parent域找到上一个顶点,并输出顶点5,以此类推,直到顶点的parent为-1,这说明逆路径就输出完毕了。

你可能感兴趣的:(数据结构基础)