深度优先搜索和广度优先搜索C语言 (紫皮书)

深度优先搜索和广度优先搜索C语言 (紫皮书)源代码在文章最后 深度优先搜索 深度优先搜索又叫 depth first search 是一种在开发爬虫早期比较常用的方法 这里我会用最易懂的方法让大家理解深度优先搜索 所谓深度优先搜索 就是找到图中的一个节点 然后依此寻找与他相关的下一个节点

大家好,我是讯享网,很高兴认识大家。

源代码在文章最后!

深度优先搜索

深度优先搜索又叫depth first search,是一种在开发爬虫早期比较常用的方法,这里我会用最易懂的方法让大家理解深度优先搜索,所谓深度优先搜索,就是找到图中的一个节点,然后依此寻找与他相关的下一个节点,形象地来说就是一条路走到黑,
而广度优先搜索就是以一个节点开头,一次访问这个节点所有有关系的节点,先横向发展,在纵向延伸。需要用图举一个例子

在这里插入图片描述
讯享网
这是一个无向图,现在要对这个无向图进行深度优先搜索。如果我们把1当作开头的节点,那么可能的寻找顺序为1->2->5->3是深度优先搜索的一条路,

第几行就是第几个节点(从0开始),在一行中,哪一列的值为1,就是说明行所代表的节点与列所代表的节点有关系。

int graph[][6] = { 
    0,1,1,1,0,0, 1,0,0,0,1,0, 1,0,0,0,1,0, 1,0,0,0,0,1, 0,1,1,0,0,0, 0,0,0,1,0,0, }; //创立无向图  

讯享网

这里可以看到这个图是沿对角线对称的,这也是无向图的特点,这个无向图总共有六个元素,就是上面图中所画的图。

要分清楚这个图中的节点是否被访问过,我们还需要一个数组visited[]来记录每个节点的访问信息。

讯享网void DFS(int graph[][6],int v,int visited[])//参数分别是图,开始搜索的节点,visited数组 { 
    printf("访问%d节点\n",v);//可以看到访问节点的顺序 visited[v] = 1;//表示被访问过 for(int w = 0;w < VexNum;w++)//寻找第v行所有没有被访问过的节点  { 
    if(graph[v][w] != 0&&!visited[w])//在一行中搜索没有被访问过的节点  { 
    DFS(graph,w,visited);//以这个节点为基础开始访问  } } } 

从这个图中就可以感受到 “一条路走到黑的特点” ,找到一个节点,标记访问之后,紧接着寻找与他有关的下一个节点,而不是遍历所有与他相关的节点,所以深度优先搜索更容易到达数据的最低端。时间复杂度是O(n+e),n是节点数,e是边数

广度优先搜索

下面是有关广度优先搜索的内容,和深度优先搜索结合起来会更加易懂。为了方便描述和理解,这里用邻接表而不是邻接矩阵来储存图之间的关系。邻接表和邻接矩阵就不做过多介绍了。
大家如果对邻接表有疑问,最好先搞清楚邻接表,不然下面的内容可能会有理解问题。

给出邻接表的储存方式
在这里插入图片描述

typedef struct ArcNode{ 
   //边节点的数据结构 int loc;//边的一个端点, struct ArcNode* nextarc;//指向与第一个图节点有关的下一个图节点 }ArcNode; typedef struct{ 
   //图中每一个节点的数据结构 int data;//节点所代表的权值 ArcNode* firstarc;//指向该结点的第一个边界点 }VNode; 

其中VNode是图中的节点,ArcNode是与VNode有关系的节点,虽然也代表了图中的节点,和VNode有区别,只是用来表示节点之间的关系
在输入节点之间的关系的时候,使用头插法比较简便,不需要向后找到链表的末尾,
其中ArcNum是图中边的总数。
插入的方法具体是:

1.获取两个有关系的节点loc1,loc2
2.将loc2打包成一个边节点,
3.因为loc1和loc2有联系,找到loc1所代表的节点,然后将loc2打包后的节点插入loc1所代表的节点和loc1的firstArc之间,就是让loc2成为loc1的firstArc,loc1的节点往后依此移动一位,
4.因为建立的是无向图,所以要对loc2所代表的图节点与loc1在建立一次关系。

讯享网for(int i = 0;i < ArcNum;i++)//获取节点之间边的关系  { 
    int loc1,loc2; scanf("%d%d",&loc1,&loc2);//输入两个相关的节点  loc1--;//从零开始计算  loc2--; ArcNode* temp1; ArcNode* p1 = (ArcNode*)malloc(sizeof(ArcNode));//建立一个新的边关系,并对其赋值  p1->loc = loc2;//使用头插法  temp1 = graph[loc1].firstarc; graph[loc1].firstarc = p1; p1->nextarc = temp1; ArcNode* temp2;//因为所建立的图为无向图,所以要将两个节点之间的关系在建立一遍  ArcNode* p2 = (ArcNode*)malloc(sizeof(ArcNode)); p2->loc = loc1; temp2 = graph[loc2].firstarc; graph[loc2].firstarc = p2; p2->nextarc = temp2; } 

在这里插入图片描述
插入完所有节点之后,就可以进行广度优先搜索了,同样,也需要一个visited[]数组来记录哪些节点已经被访问过,因为采用的是邻接表的储存方法,所以很容易能知道一个节点的所有相关节点,只需要从头节点根据指针一直想后搜索,直到指针的值是NULL为止。

在遍历的时候,需要用到循环队列在访问一个节点的关联节点时,将他的关联节点依此入队,这个节点访问完成后,下一次从队尾出队一个元素,在对这个元素进行搜索,重复上述的入队过程,直到所有节点都被访问到。

使用循环队列的原因是因为节省空间。需要对队列指针进行取余,防止越界。

void BFS(VNode graph[],int visited[],int v)//给出图,访问数组还有一个开始顶点 { 
    printf("访问节点%d\n",v); visited[v] = 1;//已经访问过 queue[PHead++] = v;//v节点入队 while(!QueueEmpty())//队列非空  { 
    if(AllVisited(visited) == 1)//所有节点都被访问过  { 
    printf("所有节点都以访问\n"); return ; } int temp = queue[PTail];//将队尾元素出队,  queue[PTail] = 100;//队列元素初始化  PTail++;//尾指针前移  PTail = PTail % 8;//避免越界  ArcNode* arc_temp = graph[temp].firstarc;//节点的第一个指针  while(arc_temp != NULL)//遍历这个节点的所又关联节点  { 
    if(visited[arc_temp->loc] == 0)//这个节点的关联节点没有被访问过 { 
    visited[arc_temp->loc] = 1;//表示已经被访问 printf("访问节点%d\n",arc_temp->loc); queue[PHead++] = arc_temp->loc;//将这个节点入队  PHead = PHead % 8;//保证不会越界  } arc_temp = arc_temp->nextarc;//寻找下一个关联节点  } } } 

如果要遍历的是一棵树的话,深度优先搜索可以很快地走到叶子节点,而广度优先搜索的路径从根节点开始向四周所有可以走的路径蔓延。

深度优先搜索代码

讯享网#include<stdio.h> int VexNum = 6; int VisitAll(int visited[],int n) { 
    for(int i = 0;i < n;i++) { 
    if(visited[i] == 0) { 
    return 0; } } return 1; } void DFS(int graph[][6],int v,int visited[]) { 
    printf("访问%d节点\n",v); visited[v] = 1;//表示被访问过 for(int w = 0;w < VexNum;w++)//寻找第v行所有没有被访问过的节点  { 
    if(graph[v][w] != 0&&!visited[w])//出现没有被访问过的节点  { 
    DFS(graph,w,visited);//以这个节点为基础开始访问  } } } int main() { 
    int graph[][6] = { 
    0,1,1,1,0,0, 1,0,0,0,1,0, 1,0,0,0,1,0, 1,0,0,0,0,1, 0,1,1,0,0,0, 0,0,0,1,0,0, }; //创立无向图  int visited[6] = { 
   0};//记录节点的访问情况1  DFS(graph,0,visited); if(VisitAll(visited,VexNum) == 1) { 
    printf("所有节点都被访问了\n"); } else { 
    while(VisitAll(visited,VexNum) == 0)//未遍历所有节点  { 
    printf("非连通图\n"); for(int i = 0;i < VexNum;i++)//随便找到一个没有遍历的节点,以他为开头 遍历  { 
    if(visited[i] == 0) DFS(graph,i,visited); } } } return 0; } 

广度优先搜索代码

#include<stdio.h> #include<stdlib.h> int VexNum = 8;//节点的个数 int ArcNum = 9;//变得个数 int PHead = 0;队列的头指针 int PTail = 0;//队列的尾指针 int queue[8] = { 
   100};//队列初始化每个值为100 typedef struct ArcNode{ 
    int loc; struct ArcNode* nextarc; }ArcNode; typedef struct{ 
    int data; ArcNode* firstarc; }VNode; int QueueEmpty() { 
    if(PHead % 8 == PTail % 8)//队列为空  { 
    return 1; } else { 
    return 0; } } int AllVisited(int visited[]) { 
    for(int i = 0;i < VexNum;i++) { 
    if(visited[i] == 0)//存在没有被访问过的节点  { 
    return 0; } } return 1; } void BFS(VNode graph[],int visited[],int v)//给出图,访问数组还有一个开始顶点 { 
    printf("访问节点%d\n",v); visited[v] = 1;//已经访问过 queue[PHead++] = v;//v节点入队 while(!QueueEmpty())//队列非空  { 
    if(AllVisited(visited) == 1)//所有节点都被访问过  { 
    printf("所有节点都以访问\n"); return ; } int temp = queue[PTail];//将队尾元素出队,  queue[PTail] = 100;//队列元素初始化  PTail++;//尾指针前移  PTail = PTail % 8;//避免越界  ArcNode* arc_temp = graph[temp].firstarc;//节点的第一个指针  while(arc_temp != NULL)//遍历这个节点的所又关联节点  { 
    if(visited[arc_temp->loc] == 0)//这个节点的关联节点没有被访问过 { 
    visited[arc_temp->loc] = 1;//表示已经被访问 printf("访问节点%d\n",arc_temp->loc); queue[PHead++] = arc_temp->loc;//将这个节点入队  PHead = PHead % 8;//保证不会越界  } arc_temp = arc_temp->nextarc;//寻找下一个关联节点  } } } int main() { 
    VNode graph[VexNum]; for(int i = 0;i < VexNum;i++)//初始化节点  { 
    graph[i].firstarc = NULL; graph[i].data = -1; } for(int i = 0;i < VexNum;i++)//获得每个结点的data值  { 
    scanf("%d",&(graph[i].data)); } for(int i = 0;i < ArcNum;i++)//获取节点之间边的关系  { 
    int loc1,loc2; scanf("%d%d",&loc1,&loc2);//输入两个相关的节点  loc1--;//从零开始计算  loc2--; ArcNode* temp1; ArcNode* p1 = (ArcNode*)malloc(sizeof(ArcNode));//建立一个新的边关系,并对其赋值  p1->loc = loc2;//使用头插法  temp1 = graph[loc1].firstarc; graph[loc1].firstarc = p1; p1->nextarc = temp1; ArcNode* temp2;//因为所建立的图为无向图,所以要将两个节点之间的关系在建立一遍  ArcNode* p2 = (ArcNode*)malloc(sizeof(ArcNode)); p2->loc = loc1; temp2 = graph[loc2].firstarc; graph[loc2].firstarc = p2; p2->nextarc = temp2; } int visited[VexNum] = { 
   0}; //初始化visited数组  BFS(graph,visited,0);//从第零个节点开始进行广度优先搜索  return 0; } 
小讯
上一篇 2025-03-13 20:52
下一篇 2025-03-05 22:16

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/51095.html