C语言 深度优先搜索和广度优先搜索

前言

C语言 深度优先搜索和广度优先搜索_第1张图片

 

深度优先搜索(DFS)广度优先搜索(BFS)是常用的图搜索算法。它们可以用于许多不同的应用,例如:

  • 解决迷宫问题:DFS和BFS可以用于寻找从起点到终点的路径。
  • 网络搜索:搜索引擎使用这些算法来构建网页索引和搜索结果。
  • 社交网络分析:DFS和BFS可以用于发现社交网络中的连通分量、关键人物和社区结构。
  • 生成树和图的遍历:DFS和BFS可以用于生成树和图的遍历,以及查找最短路径和最小生成树等。
  • 人工智能:DFS和BFS可以用于训练神经网络、搜索游戏树和解决决策问题等。

总之,DFS和BFS是非常常见和有用的算法,它们可以应用于许多不同的领域,包括计算机科学、人工智能、生物学、社会网络等。


 不太懂的看视频  QWQ(来自@码农论坛)

深度与广度优先搜索


深度优先搜索

深度优先搜索一般通过递归实现,也可以通过模拟栈实现。

基本流程如下:

1.创建一个栈并将起始顶点压入栈中。

2.当栈不为空时,进行以下操作:

  • 弹出栈顶元素,并将其标记为已访问。
  • 将该顶点的未被访问过的邻接点压入栈中。

3.重复步骤 2 直到栈为空。

这是算法递归实现函数:

//递归深度优先遍历
void DFS(ALGraph* G, int v, int* visited) {
	printf("%c ", G->vertices[v].data);//输出顶点v
	visited[v] = 1;//标记顶点v,表示已遍历
	ArcNode* p = G->vertices[v].first;//p指向v第一条依附顶点v的边
	while (p != NULL) {
		//递归遍历顶点v未访问的邻接点
		if (!visited[p->adjvex]) {
			DFS(G, p->adjvex, visited);
		}
		p = p->next;
	}
}

广度优先搜索

广度优先搜索使用队列来实现。

基本流程如下:

1.创建一个队列,并将起始顶点入队。
2.当队列不为空时,进行以下操作:

  • 出队一个顶点,输出该顶点。
  • 将该顶点的所有未被访问过的邻接点入队,并把它标记为已访问。

重复步骤 2 直到队列为空。

//广度优先遍历
void BFS(ALGraph* G, int* visited) {
	int e;//用来储存出队的顶点的顶点数组中的下标
	ArcNode* p = NULL;
	Queue* Q = InitQueue();//初始化队列
	Push(Q, 0);//把第一个顶点入队
	visited[0] = 1;//标记第一个顶点
	//循环结束条件为空队
	while (Pop(Q, &e)) {
		printf("%c ", G->vertices[e].data);//输出出队顶点
		p = G->vertices[e].first;//指针p指向依附顶点e的第一条边
		//将顶点e未访问的邻接点入队并标记
		while (p != NULL) {
			if (!visited[p->adjvex]) {
				Push(Q, p->adjvex);
				visited[p->adjvex] = 1;
			}
			p = p->next;
		}
	}
}

 


 运行代码建立如下图所示的无向图并用深度优先搜索和广度优先搜索遍历:

C语言 深度优先搜索和广度优先搜索_第2张图片

 运行结果如下:

C语言 深度优先搜索和广度优先搜索_第3张图片

 


源代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
#include
#define MVNum 100  //最大顶点数
typedef struct ArcNode {  //边表结点
	int adjvex;//邻接点在顶点数组中的下标
	struct ArcNode* next;//指向下一条边的指针
}ArcNode;

typedef struct VNode {   //顶点信息结构体
	char data;
	ArcNode* first;//指向第一条依附于该顶点的边的指针
}VNode, AdjList[MVNum];

typedef struct {   //图结构体
	AdjList vertices;//邻接表
	int vexnum, arcnum;//顶点数和边数
}ALGraph;

//查找
int LocateVex(ALGraph* G, char v) {
	int i;
	for (i = 0; i < G->vexnum; i++) {
		if (G->vertices[i].data == v) {
			return i;
		}
	}
	return -1;
}

//无向图邻接表的创建
ALGraph* CreateALGraph() {
	int i, j, k;
	char v1, v2;
	ALGraph* G = malloc(sizeof(ALGraph));
	printf("输入顶点数和边数:\n");
	scanf("%d%d", &G->vexnum, &G->arcnum);
	getchar();//吸收换行符
	printf("依次输入顶点信息:\n");
	for (i = 0; i < G->vexnum; i++) {
		scanf("%c", &G->vertices[i].data);
		G->vertices[i].first = NULL;
	}
	getchar();//吸收换行符
	//构造边表
	for (k = 0; k < G->arcnum; k++) {
		printf("输入一条边依附的两个顶点:\n");
		scanf("%c%c", &v1, &v2);
		getchar();//吸收换行符
		i = LocateVex(G, v1), j = LocateVex(G, v2);//确定v1、v2在邻接表数组中的下标
		ArcNode* p1 = malloc(sizeof(ArcNode));//生成新的边结点*p1
		p1->adjvex = i;//邻接点序号为i
		p1->next = G->vertices[j].first;//头插法插到顶点vj的边表头部
		G->vertices[j].first = p1;
		//因为是无向图,所以生成对称的边结点*p2
		ArcNode* p2 = malloc(sizeof(ArcNode));
		p2->adjvex = j;
		p2->next = G->vertices[i].first;
		G->vertices[i].first = p2;
	}
	return G;
}

//输出邻接表
void print(ALGraph* G) {
	int i;
	for (i = 0; i < G->vexnum; i++) {
		printf("顶点%c的邻结点有:", G->vertices[i].data);
		ArcNode* p = G->vertices[i].first;
		while (p != NULL) {
			printf(" %c", G->vertices[p->adjvex].data);
			p = p->next;
		}
		printf("\n");
	}
}

//递归深度优先遍历
void DFS(ALGraph* G, int v, int* visited) {
	printf("%c ", G->vertices[v].data);//输出顶点v
	visited[v] = 1;//标记顶点v,表示已遍历
	ArcNode* p = G->vertices[v].first;//p指向v第一条依附顶点v的边
	while (p != NULL) {
		//递归遍历顶点v未访问的邻接点
		if (!visited[p->adjvex]) {
			DFS(G, p->adjvex, visited);
		}
		p = p->next;
	}
}


typedef struct QNode {
	int data;
	struct QNode* next;
}QNode;
typedef struct {
	QNode* front;
	QNode* rear;
}Queue;
Queue* InitQueue() {
	Queue* Q = malloc(sizeof(Queue));
	QNode* t = malloc(sizeof(QNode));
	t->next = NULL;
	Q->front = t;
	Q->rear = t;
	return Q;
}
void Push(Queue* Q, int e) {
	QNode* t = malloc(sizeof(QNode));
	t->data = e;
	t->next = NULL;
	Q->rear->next = t;
	Q->rear = t;
}
bool Pop(Queue* Q, int* e) {
	if (Q->front == Q->rear)	return false;
	QNode* p = Q->front->next;
	*e = p->data;
	if (Q->rear == p) {
		Q->rear = Q->front;
	}
	Q->front->next = p->next;
	free(p);
	return true;
}

//广度优先遍历
void BFS(ALGraph* G, int* visited) {
	int e;//用来储存出队的顶点的顶点数组中的下标
	ArcNode* p = NULL;
	Queue* Q = InitQueue();//初始化队列
	Push(Q, 0);//把第一个顶点入队
	visited[0] = 1;//标记第一个顶点
	//循环结束条件为空队
	while (Pop(Q, &e)) {
		printf("%c ", G->vertices[e].data);//输出出队顶点
		p = G->vertices[e].first;//指针p指向依附顶点e的第一条边
		//将顶点e未访问的邻接点入队并标记
		while (p != NULL) {
			if (!visited[p->adjvex]) {
				Push(Q, p->adjvex);
				visited[p->adjvex] = 1;
			}
			p = p->next;
		}
	}
}

int main() {
	ALGraph* G = CreateALGraph();
	print(G);
	int visited_1[MVNum] = { 0 };
	printf("深度优先遍历结果:\n");
	DFS(G, 0, visited_1);
	int visited_2[MVNum] = { 0 };
	printf("\n广度优先遍历结果:\n");
	BFS(G, visited_2);
}

总结

  • 深度优先搜索是从一个节点开始,沿着一条路径一直走到底,如果走到了死路,就回退到上一个节点,再继续走其他路径,直到遍历完整个图。
  • 广度优先搜索是从一个节点开始,先访问这个节点的所有邻居节点,然后依次访问这些邻居节点的邻居节点,直到遍历完整个图。

两者的主要区别在于搜索的顺序不同,深度优先搜索的搜索顺序是一条路走到黑,直到遇到死路才回退,而广度优先搜索的搜索顺序是逐层遍历,先遍历距离起始节点为1的节点,再遍历距离起始节点为2的节点,以此类推。

C语言 深度优先搜索和广度优先搜索_第4张图片

 

 

你可能感兴趣的:(数据结构与算法,深度优先,c语言,宽度优先)