美文网首页
16-图的深搜和广搜二

16-图的深搜和广搜二

作者: 董泽平 | 来源:发表于2019-09-29 08:39 被阅读0次

图的深搜和广搜

前面一篇是利用深搜和广搜进行图的顶点的遍历,今天我们则是根据起点和终点位置进行路径的搜索。

图的深搜算法

问题:假设现在有一无向图,我现在要给你一个起始点和终点,如果可以走通请输出一条简单路径,不能则返回无路径。

思考:我们可以考虑用深度搜索去求解此问题,我们假设用邻接矩阵存储这个图。我们可以设计一个数组去保存搜索过程的路径。

注意点:算法的设计关键就是利用深搜递归可以回退参数的特点去求解,但是由于c语言的普通数组,传递的参数都是实参,无法进行回退,所以我们需要自定义伪数组去实现真正的形参,这样我们可以回退数组的结果。

深搜步骤

  • 设计一个空数组,用于保存搜索整个过程经过的点,数组必须是可以回退的形参(数组作为函数参数比较特殊,它是引用传递,函数的直接修改)
  • 在搜索的递归函数开始时,初始将起点添加到数组里,然后凡是和起点有关的都进行递归,于是到了第二层递归时,和起点有关的一个点又作为起点放入新的形参数组继续调用递归,,直到发现某个点等于终点,就输出数组的保存的路径,递归结束。

图示案例

我先用个形象的图,演示下递归处理的过程,假设我们要搜索A到F是否有一条简单路径。
我们就是让A先进去第一层递归,把A放入数组,接着B,C,D都和A有关联,依次进入各自的递归函数,然后进入B,C,D的那些点带着自己的数组,又作为起点将和它相连的点依次进入递归函数,整个过程就有以下搜索过程

  • A-->B-->E-->F
  • A-->C-->E-->F
  • A-->D-->G-->H
graph12.jpg

深搜代码

//深搜的辅助操作
void Find_Path(struct MGraph *g, char obj1, char obj2)
{
    int index1, index2,*temp;
    struct Array arr;
    arr.len = 0;
    temp = (int*)malloc(sizeof(int) * g->numVretexes);
    for (int i = 0; i < g->numVretexes; i++)
    {
        if (g->vetex[i] == obj1)
        {
            index1 = i;
        }
        if (g->vetex[i] == obj2)
        {
            index2 = i;
        }
        temp[i] = 0;
    }
    DFS_Search(g, arr, temp, index1, index2);
}

//深搜的核心
void DFS_Search(struct MGraph *g, struct Array arr,int *temp, int obj1, int obj2)
{
    temp[obj1] = 1;
    arr.data[arr.len++] = obj1;
    if (obj1 == obj2)//找到了路径,输出路径
    {
        for (int i = 0; i < arr.len; i++)
        {
            printf("%c ", g->vetex[i]);
        }
        printf("\n");
    }
    for (int j = 0; j < g->numVretexes; j++)
    {
        if (g->data[obj1][j] != 0 && temp[j]==0)//有关联的点
        {
            DFS_Search(g, arr,temp, j, obj2);
        }
    }
}

图的广搜算法

问题:假设现在有一无向图,我现在要给你一个起始点和终点,请输出一条最短的行走方案。(最短就是指走过的边数最少)

思考:此时的问题已经是在寻找路径的基础上增加了一条最短路径的问题,注意此处的最短路径不是说求带权值的最短路径,此处的最短路径求的是按边的个数计算。走过的边最少的路径。

方案: 因为广度优先遍历,是逐层逐层的找,所以它肯定会在第一时间内找到我们要找的点,当然它对应的路径也就是经过边的个数一定是最少的。我们在进行广度优先遍历的基础上为每个点增加前驱标记,标记每个点的前驱是谁,这样我们就可以回退输出最短路径了。忘记广度优先遍历的可以看前一篇关于广度优先遍历的介绍。

过程演示

graph13.jpg

假设我们要寻找点A到点E的最短路径问题。

  1. 初始化队列queue和前驱数组path,并让点A入队列。
队列元素 A
data A B C D E F
前驱顶点

2.出队一个元素,A出队列,和A有关联的点都入队列,即B与F都入队列,修改入队点B和F的前驱是A

队列元素 B F
data A B C D E F
前驱顶点 A A

3.出队一个元素,B出队列,和B有关的都入队列,被访问的点不用入队列。所以C和D入队列,修改点C和点D的前驱是B

队列元素 F C D
data A B C D E F
前驱顶点 A B B A

4.出队列一个元素,所以F出队列,和F有关的都入队列,所以E入队列,修改点E的前驱是F,此时E节点找到了,直接退出。

队列元素 C D E
data A B C D E F
前驱顶点 A B B F A

好了,我们只需要查看最终的前驱数组,就可以得到最短路径了,终点E的前驱是F,F的前驱是A,到达了起点A,所以最终的最短路径就是A-F-E了。

广搜代码

void Find_Path(struct MGraph *g, char obj1, char obj2)
{
    int index1, index2, *temp,*pre,*queue,front,rear,num;
    temp = (int*)malloc(sizeof(int) * g->numVretexes);
    queue = (int*)malloc(sizeof(int) * g->numVretexes);//辅助队列
    pre = (int*)malloc(sizeof(int) * g->numVretexes);
    front = rear = 0;
    for (int i = 0; i < g->numVretexes; i++)
    {
        temp[i] = 0;
        pre[i] = -1;//前驱顶点
        if (obj1 == g->vetex[i])
        {
            index1 = i;
        }
        if (obj2 == g->vetex[i])
        {
            index2 = i;
        }
    }
    queue[rear++] = index1;
    temp[index1] = 1;
    while (front != rear)
    {
        num = queue[front++];
        if (num == index2)//找到了目标点,逆序打印路径
        {
            while (pre[num]!=-1)
            {
                printf("%c ", g->vetex[num]);
                num = pre[num];
            }
            printf("%c ", g->vetex[num]);
            printf("\n");
        }
        //出队列时,将所有有关联的点入队列
        for (int i = 0; i < g->numVretexes; i++)
        {
            if (g->data[num][i] != 0 && temp[i] == 0)
            {
                temp[i] = 1;
                queue[rear++] = i;
                pre[i] = num;//设置顶点的前驱
            }
        }
    }
}

获取完整代码

我分别用C,C++,JAVA三种主流语言编写了完整代码,请大家指导批正,一起学习。

点击查看

相关文章

  • 16-图的深搜和广搜二

    图的深搜和广搜 前面一篇是利用深搜和广搜进行图的顶点的遍历,今天我们则是根据起点和终点位置进行路径的搜索。 图的深...

  • 15-图的深搜和广搜一

    图的深度和广搜优先遍历 深度优先遍历 深度优先搜索就好比走迷宫,当走到一个岔路口时,你随机选择一条路往下走,当发现...

  • 简单的搜索 ----(dfs) 和 (bfs)简单的

    广搜(bfs)和 深搜(dfs) 先从广搜说起(bfs)广搜,字面感觉就是广面的搜索,其实就是这样的,我认为可以把...

  • 搜索算法

    搜索一般指的是深度搜索和广度搜索。这两种搜索算法都有固定的格式,下面是深搜和广搜的固定套路: 1.广搜(BFS) ...

  • Java 算法-拓扑排序(深搜或者广搜)

      说实话,在数据结构中,拓扑排序我掌握的不是很好,今天在lintCode上面做了关于拓扑排序的题,才开始还是有点...

  • 广搜

    #include#include#includeusingnamespacestd;constintMAXN=10...

  • leetcode算法题解(Java版)-16-动态规划(单词包含

    摘要: 碰到二叉树的问题,差不多就是深搜、广搜,递归那方面想想了,当然如果要考虑一下空间、时间,还需要进行剪枝和压...

  • 二叉树的几种遍历方式(附 LeetCode 水题)

    正文之前 闲得无聊去刷 LeetCode 的时候做了一点深搜和广搜的题,但是树的遍历方式还没有写过总结,今天刚好总...

  • 搜图神器 全网搜图

    ◈推荐正文 ◈资源获取与安装 ◈END

  • 【 数据结构 & 算法 】—— 搜索

    思维导图 例1:岛屿数量(medium)(深搜、宽搜) 用一个二维数组代表一张地图,这张地图由字符 " 0 " 与...

网友评论

      本文标题:16-图的深搜和广搜二

      本文链接:https://www.haomeiwen.com/subject/fhhnyctx.html