【九】【数据结构】深度优先和广度优先遍历,代码简单实现,深度解析

代码实现

这个代码是在图的邻接矩阵(无项、有权)的代码的基础上,添加了DFS和BFS两个函数,DFS是深度优先遍历图,BFS是广度优先遍历图,并且修改主函数代码,图的邻接矩阵(无项、有权)的代码具体请查看 【C语言\数据结构】图之邻接矩阵(无向、有权)代码简单实现,这里就不过多赘述。

编写深度优先DFS函数

 
void _DFS(graph g,int vex,int visit[]){
    visit[vex]=1;
    printf("%d ",vex);
    for(int i=1;i<=g.vexnum;i++){
        if(visit[i]==0&&g.arcs[vex][i]!=0&&g.arcs[vex][i]!=INFINITY){
            _DFS(g,i,visit);
        }
    }
 }
void DFS(graph g,int vex){
    int visit[g.vexnum+1]={0};
    printf("深度优先遍历:\n");
    _DFS(g,vex,visit);
 }

首先引入集合的概念,定义visit数组,visit[i]=x表示顶点i在x集合中,此代码规定的集合为0或者1,也就是x的取值只能为0或者1,0所代表的集合是顶点还没有被访问过,而1所代表的集合是顶点已经被访问过。

因为我们的顶点是从1开始,所以visit数组同样需要舍弃第一个元素,达到统一的效果,故需要多定义一个空间,visit数组初始化为0,表示所有的顶点一开始都没有被访问过。

接着进入_DFS递归函数中,对指定顶点vex进行深度优先遍历。

首先遍历顶点vex,打印该顶点,并把该顶点归入集合1中,表示该顶点已经被访问过了。

然后依次循环遍历与顶点vex相连的其他顶点,注意,每遍历顶点vex的一个其他顶点,就对其深度优先遍历。

判断其他顶点的条件是,vex顶点与i顶点有边,并且i顶点还没有被访问过。

下面是一个例子,以及这个例子对应的递归图,红色的箭头一直往深处走,走到底从粉色的箭头递归回来。

编写广度优先BFS函数

 
void BFS(graph g,int vex){
    int size=g.vexnum+1;
    int visit[size]={0};
    int queue[size];
    int front=0;
    int rear=0;
    printf("广度优先遍历:\n");
    visit[vex]=1;
    printf("%d ",vex);
    queue[rear++]=vex;
    while(front!=rear){
        int newvex=queue[front];
        front++;
        for(int i=1;i<=g.vexnum;i++){
            if(visit[i]==0&&g.arcs[newvex][i]!=0&&g.arcs[newvex][i]!=INFINITY){
                printf("%d ",i);
                visit[i]=1;
                queue[rear++]=i;
            }
        }
    }
    
}

根据集合思想,定义visit数组,以及队列queue,队列的大小定义为size大小,可以存储比图顶点数还多一个的数据,所以这个队列的队尾rear一定不会越界,rear和front直接++不用构造循环队列。

首先遍历vex顶点,打印该顶点,并把该顶点归于1集合中,1集合是被访问过的集合。

接着把该顶点入队。

如果队列不为空,就去队头的顶点,并进行pop操作,也就是front++。

接着依次访问newvex的每一个连接顶点,每遍历一个顶点就打印并修正集合,然后入队,直到队列为空。


完整代码

 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 100
 #define INFINITY 9999
enum graphType {DG, UG, DN, UN}; //图的类型定义:有向图,无向图,有向网,无项网
typedef char vertexType;
typedef struct {
    vertexType vexs[MAX];
    int arcs[MAX][MAX];
    int vexnum, arcnum;
    graphType kind;
 } graph;

void initGraph(graph &g) {
    
     g.kind = UN;
    printf("输入顶点数和边数:\n");
    scanf("%d%d", &g.vexnum, &g.arcnum);
    for (int i = 1; i <= g.vexnum; i++) {
        g.vexs[i] = i;
    }
    for (int i = 1; i <= g.vexnum; i++) {
        for (int j = 1; j < g.vexnum; j++) {
            if (i == j) g.arcs[i][j] = 0;
            else g.arcs[i][j] = INFINITY;
        }
    }
 }

void createGraph(graph &g) {
    int start_index, end_index, weight;
    
     printf("输入每条边的起点终点下标和边的权重:\n");
    for (int i = 1; i <= g.arcnum; i++) {
        scanf("%d%d%d", &start_index, &end_index, &weight);
        g.arcs[start_index][end_index] = weight;
        g.arcs[end_index][start_index] = weight;
    }
 }

void showGraph(graph &g) {
    printf("邻接矩阵:\n");
    for (int i = 1; i <= g.vexnum; i++) {
        for (int j = 1; j <= g.vexnum; j++) {
            printf("%d ", g.arcs[i][j]);
        }
        printf("\n");
    }
 }
void _DFS(graph g,int vex,int visit[]){
    visit[vex]=1;
    printf("%d ",vex);
    for(int i=1;i<=g.vexnum;i++){
        if(visit[i]==0&&g.arcs[vex][i]!=0&&g.arcs[vex][i]!=INFINITY){
            _DFS(g,i,visit);
        }
    }
 }
void DFS(graph g,int vex){
    int visit[g.vexnum+1]={0};
    printf("深度优先遍历:\n");
    _DFS(g,vex,visit);
 }

void BFS(graph g,int vex){
    int size=g.vexnum+1;
    int visit[size]={0};
    int queue[size];
    int front=0;
    int rear=0;
    printf("广度优先遍历:\n");
    visit[vex]=1;
    printf("%d ",vex);
    queue[rear++]=vex;
    while(front!=rear){
        int newvex=queue[front];
        front++;
        for(int i=1;i<=g.vexnum;i++){
            if(visit[i]==0&&g.arcs[newvex][i]!=0&&g.arcs[newvex][i]!=INFINITY){
                printf("%d ",i);
                visit[i]=1;
                queue[rear++]=i;
            }
        }
    }
    
}

int main() {
    graph g;
    initGraph(g);
    createGraph(g);
    showGraph(g);
    DFS(g,1);
    printf("\n");
    BFS(g,1);
    
}
/*测试用例:
 5 8
 1 2 1
 1 5 4
 1 3 3
 2 4 2
 4 5 4
 3 4 1
 2 3 2
 3 5 1
 */

代码运行截图:

可以验证,深度优先遍历和广度优先遍历没有问题。


结尾

今天学习了深度优先和广度优先遍历图,深度优先遍历需要利用递归,也就是栈的知识,先进后出,广度优先遍历需要利用队列,先进先出。两个遍历都需要利用集合的思想,定义visit判断顶点是否被访问过。

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

  • 31
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

妖精七七_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值