广度优先搜索(BFS)和深度优先搜索(DFS)

广度优先搜索(BFS)和深度优先搜索(DFS)

 

目录

一、邻接矩阵和邻接表

1.1邻接矩阵创建图

1.2邻接表创建图

二、广度优先搜索

2.1使用邻接矩阵表示图的广度优先搜索

2.2使用邻接表表示图的广度优先搜索

2.3非连通图的广度优先搜索

三、深度优先搜索

3.1使用邻接矩阵表示图的深度优先搜索

3.2使用邻接表表示图的深度优先搜索

 

一、邻接矩阵和邻接表

1.1邻接矩阵

思路

图的邻接矩阵存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IHbQN8th-1666313142240)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221020091723440.png)]

 

代码实现
#include <iostream>
using namespace std;
#include <queue>
#define MVNum 100
queue<char> q;
bool visited[MVNum];
//邻接矩阵存储表示
struct AMGrapy
{
	char vexs[MVNum];//顶点表
	int arcs[MVNum][MVNum];//邻接矩阵
	int vexnum, arcnum;//当前的顶点数和边数
};
//找到顶点V的对应下标
int LocateVex(AMGrapy& G, char v)
{
	for (int i = 0; i < G.vexnum; i++)
	{
		if (G.vexs[i] == v)
		{
			return i;
		}
	}
}
//采用邻接矩阵表示法,创建无向图G
int CreateUGD_1(AMGrapy& G)
{
	int i, j, k;
	char v1, v2;
	scanf("%d%d", &G.vexnum, &G.vexnum);//输入总顶点数和总边数
	getchar();//获取'\0', 以免对之后字符的输入有影响
	for (i = 0; i < G.vexnum; i++)
	{
		scanf("%c", &G.vexs[i]);
	}

	for (i = 0; i < G.vexnum; i++)
	{
		for (j = 0; j < G.vexnum; j++)
		{
			G.arcs[i][j] = 0;
		}
	}

	for (k = 0; k < G.arcnum; k++)
	{
		getchar();
		scanf("%c%c", &v1, &v2);
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
		G.arcs[i][j] = G.arcs[j][i] = 1;
	}
	return 1;
}

返回目录

 

1.2使用邻接表创建图

思路

图的邻接表存储方式是用一个数组和多个链表来表示图。里面的元素是各个结点的信息,元素的内容有数据域,还有边结点类的与表头相连的第一个元素的指针,边结点类包含指向的元素在数组中的秩,下一个边结点的指针,权重,每当表头的链表多增加一个元素,将此元素的指针放在新增加元素的next指针中,然后把该指针设置为表头元素的第一条边[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tpdNBqzu-1666313142242)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221020120947627.png)]

 

代码实现

#include <iostream>
using namespace std;
#define MVNum 100
// 边结点类
struct ArcNode
{
	int adjvex; //该条边所指向的顶点的下标
	ArcNode* nextarc; // 指向下一条边的指针
	int info;//与边相应的信息
};
//表头结点类
typedef struct VexNode
{
	char data; //顶点的数据
	ArcNode* firstarc;  //第一个指向的边结点的指针
}AdjList[MVNum];
//关联表图类
struct ALGrapy
{
	AdjList vertices;
	int vexnum, arcnum;
};
// 找到顶点对应下标
int LocateVex(ALGrapy& G, char v0)
{
	for (int i = 0; i < G.vexnum; i++)
	{
		if (v0 == G.vertices[i].data)
		{
			return i;
		}
	}
}

int CreateUDG_2(ALGrapy& G)
{
	int i, j, k;
	char v1, v2;
	scanf("%d %d", &G.vexnum, &G.arcnum);
	getchar();
	for (i = 0; i < G.vexnum; i++)//初始化存储表头结点的数组
	{
		scanf("%c", &G.vertices[i].data);
		G.vertices[i].firstarc = NULL;
	}

	for (k = 0; k < G.arcnum; k++)
	{
		getchar();
		scanf("%c%c", &v1, &v2);
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
		ArcNode* p1 = new ArcNode;
		p1->adjvex = j;
		p1->nextarc = G.vertices[i].firstarc;
		G.vertices[i].firstarc = p1;
		ArcNode* p2 = new ArcNode;
		p2->adjvex = i;
		p2->nextarc = G.vertices[j].firstarc;
		G.vertices[j].firstarc = p2;
	}
	return 1;
}
//递归清除一个表头的在堆区开辟的内存空间,先从最深处开始释放
void clearLine(ArcNode* arc)
{
	if (arc->nextarc)
	{
		clearLine(arc->nextarc);
	}
	delete arc;
}
//清除在堆区开辟的内存空间
void clearGrapy(ALGrapy& G)
{
	for (int i = 0; i < G.vexnum; i++)
	{
		if (G.vertices[i].firstarc)
		{
			clearLine(G.vertices[i].firstarc);
		}
	}
}

返回目录

 

二、广度优先搜索

2.1使用邻接矩阵表示图的广度优先搜索

思路

准备一个字符队列存放已经访问过的结点,首先将起点先访问,并且将是否访问的数组置为1,然后再把它推入队列中,依次出队列,然后找到与它相连的结点并且没有被访问过的结点,然后将其访问并把它推入队列,直到队列为空说明所有的结点访问完毕

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eChIQBGN-1666313142242)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221019191851980.png)]

 

代码实现
#include <iostream>
using namespace std;
#include <queue>
#define MVNum 100
queue<char> q;
bool visited[MVNum] = { 0 };
//邻接矩阵存储表示
struct AMGrapy
{
	char vexs[MVNum];//顶点表
	int arcs[MVNum][MVNum];//邻接矩阵
	int vexnum, arcnum;//当前的顶点数和边数
};
//找到顶点V的对应下标
int LocateVex(AMGrapy& G, char v)
{
	for (int i = 0; i < G.vexnum; i++)
	{
		if (G.vexs[i] == v)
		{
			return i;
		}
	}
}
//采用邻接矩阵表示法,创建无向图G
int CreateUGD_1(AMGrapy& G)
{
	int i, j, k;
	char v1, v2;
	scanf("%d %d", &G.vexnum, &G.arcnum);//输入总顶点数和总边数
	getchar();//获取'\n', 以免对之后字符的输入有影响
	for (i = 0; i < G.vexnum; i++)
	{
		scanf("%c", &G.vexs[i]);
	}

	for (i = 0; i < G.vexnum; i++)
	{
		for (j = 0; j < G.vexnum; j++)
		{
			G.arcs[i][j] = 0;
		}
	}

	for (k = 0; k < G.arcnum; k++)
	{
		getchar();
		scanf("%c%c", &v1, &v2);
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
		G.arcs[i][j] = G.arcs[j][i] = 1;
	}
	return 1;
}

void BFS_AM(AMGrapy& G, char v0)
{
	int i, v;
	char w, u;
	v = LocateVex(G, v0);
	cout << v0 << " ";
	visited[v] = true;
	q.push(v0);
	while (!q.empty())
	{
		u = q.front();
		q.pop();
		v = LocateVex(G, u);
		for (i = 0; i < G.vexnum; i++)
		{
			w = G.vexs[i];
			if (G.arcs[v][i] && !visited[i])
			{
				cout << w << " ";
				visited[i] = true;
				q.push(w);
			}
		}
	}
}

int main()
{
	AMGrapy G;
	char v0 = 'A';
	CreateUGD_1(G);
	BFS_AM(G, v0);
    cout << endl;
    system("pause");
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f0zzYjbl-1666313142243)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221020001909820.png)]

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j4l5ofEe-1666313142244)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221020091013549.png)]

返回目录

 

2.2使用邻接表表示图的广度优先搜索

思路

准备一个字符队列存放已经访问过的结点,首先将起点先访问,并且将是否访问的数组置为1,然后再把它推入队列中,依次出队列,然后找到与它相连的结点并且没有被访问过的结点,然后将其访问并把它推入队列,直到队列为空说明所有的结点访问完毕

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Eo5eSGT-1666313142245)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221020200422973.png)]

 

代码实现
#include <iostream>
using namespace std;
#define MVNum 100
#include <queue>;
queue<char> q;
bool visited[MVNum] = { 0 };
// 边结点类
struct ArcNode
{
	int adjvex; //该条边所指向的顶点的下标
	ArcNode* nextarc; // 指向下一条边的指针
	int info;//与边相应的信息
};
//表头结点类
typedef struct VexNode
{
	char data; //顶点的数据
	ArcNode* firstarc;  //第一个指向的边结点的指针
}AdjList[MVNum];
//关联表图类
struct ALGrapy
{
	AdjList vertices;
	int vexnum, arcnum;
};
// 找到顶点对应下标
int LocateVex(ALGrapy& G, char v0)
{
	for (int i = 0; i < G.vexnum; i++)
	{
		if (v0 == G.vertices[i].data)
		{
			return i;
		}
	}
}

int CreateUDG_2(ALGrapy& G)
{
	int i, j, k;
	char v1, v2;
	scanf("%d %d", &G.vexnum, &G.arcnum);
	getchar();
	for (i = 0; i < G.vexnum; i++)//初始化存储表头结点的数组
	{
		scanf("%c", &G.vertices[i].data);
		G.vertices[i].firstarc = NULL;
	}

	for (k = 0; k < G.arcnum; k++)
	{
		getchar();
		scanf("%c%c", &v1, &v2);
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
		ArcNode* p1 = new ArcNode;
		p1->adjvex = j;
		p1->nextarc = G.vertices[i].firstarc;
		G.vertices[i].firstarc = p1;
		ArcNode* p2 = new ArcNode;
		p2->adjvex = i;
		p2->nextarc = G.vertices[j].firstarc;
		G.vertices[j].firstarc = p2;
	}
	return 1;
}
//递归清除一个表头的在堆区开辟的内存空间,先从最深处开始释放
void clearLine(ArcNode* arc)
{
	if (arc->nextarc)
	{
		clearLine(arc->nextarc);
	}
	delete arc;
}
//清除在堆区开辟的内存空间
void clearGrapy(ALGrapy& G)
{
	for (int i = 0; i < G.vexnum; i++)
	{
		if (G.vertices[i].firstarc)
		{
			clearLine(G.vertices[i].firstarc);
		}
	}
}

void BFS_AL(ALGrapy& G, char v0)
{
	int v;
	char u;
	ArcNode* p;
	v = LocateVex(G, v0);
	cout << v0 << " ";
	visited[v] = 1;
	q.push(v0);
	while (!q.empty())
	{
		u = q.front();
		q.pop();
		v = LocateVex(G, u);
		for (p = G.vertices[v].firstarc; p; p = p->nextarc )
		{
			if (!visited[p->adjvex])
			{
				cout << G.vertices[p->adjvex].data << " ";
				visited[p->adjvex] = 1;
				q.push(G.vertices[p->adjvex].data);
			}
		}
	}
}

int main()
{
	ALGrapy G;
	char v0 = 'A';
	CreateUDG_2(G);
	BFS_AL(G, v0);
	cout << endl;
	clearGrapy(G);
	system("pause");
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qCmm706j-1666313142245)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221020195317791.png)]

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p9VxUhYV-1666313142245)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221020195245788.png)]

返回目录

 

2.3非连通图的广度优先搜索

思路

遍历所有的顶点的状态, 只有未访问的结点才采取广度优先搜索算法,这一连通子图的所有结点就会被访问,然后只有遇到未访问的,与这一子图非连通的结点才会继续采取广度优先搜索,直到所有的状态遍历完成。即所有的子图都已访问

 

代码实现
#include <iostream>
using namespace std;
#include <queue>
#define MVNum 100
queue<char> q;
bool visited[MVNum] = { 0 };
//邻接矩阵存储表示
struct AMGrapy
{
	char vexs[MVNum];//顶点表
	int arcs[MVNum][MVNum];//邻接矩阵
	int vexnum, arcnum;//当前的顶点数和边数
};
//找到顶点V的对应下标
int LocateVex(AMGrapy& G, char v)
{
	for (int i = 0; i < G.vexnum; i++)
	{
		if (G.vexs[i] == v)
		{
			return i;
		}
	}
}
//采用邻接矩阵表示法,创建无向图G
int CreateUDG_1(AMGrapy& G)
{
	int i, j, k;
	char v1, v2;
	scanf("%d %d", &G.vexnum, &G.arcnum);//输入总顶点数和总边数
	getchar();//获取'\n', 以免对之后字符的输入有影响
	for (i = 0; i < G.vexnum; i++)
	{
		scanf("%c", &G.vexs[i]);
	}

	for (i = 0; i < G.vexnum; i++)
	{
		for (j = 0; j < G.vexnum; j++)
		{
			G.arcs[i][j] = 0;
		}
	}

	for (k = 0; k < G.arcnum; k++)
	{
		getchar();
		scanf("%c%c", &v1, &v2);
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
		G.arcs[i][j] = G.arcs[j][i] = 1;
	}
	return 1;
}

void BFS_AM(AMGrapy& G, char v0)
{
	int i, v;
	char w, u;
	v = LocateVex(G, v0);
	cout << v0 << " ";
	visited[v] = true;
	q.push(v0);
	while (!q.empty())
	{
		u = q.front();
		q.pop();
		v = LocateVex(G, u);
		for (i = 0; i < G.vexnum; i++)
		{
			w = G.vexs[i];
			if (G.arcs[v][i] && !visited[i])
			{
				cout << w << " ";
				visited[i] = true;
				q.push(w);
			}
		}
	}
}

void BFSTraverse(AMGrapy& G)
{
	for (int i = 0; i < G.vexnum; i++)
	{
		if (!visited[i])
		{
			BFS_AM(G, G.vexs[i]);
			cout << endl;
		}
	}
}

int main()
{
	AMGrapy G;
	CreateUDG_1(G);
	BFSTraverse(G);
	system("pause");
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nGaTci7w-1666313142246)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221020204803255.png)]

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xdQCFhkL-1666313142246)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221020204936043.png)]

返回目录

 

三、深度优先搜索

3.1使用邻接矩阵表示图的深度优先搜索

思路

首先访问根结点,然后找出与根结点相连且没有被访问过的结点,然后对它递归调用深度优先搜索,直到平凡的情况与结点不相连接,回溯至上一级调用,直到一直回溯到对根结点的调用,即深度优先搜索完成

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Us31CEvx-1666313142247)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221021001855646.png)]

 

代码实现
#include <iostream>
using namespace std;
#define MVNum 100
bool visited[MVNum] = { 0 };
//邻接矩阵存储表示
struct AMGrapy
{
	char vexs[MVNum];//顶点表
	int arcs[MVNum][MVNum];//邻接矩阵
	int vexnum, arcnum;//当前的顶点数和边数
};
//找到顶点V的对应下标
int LocateVex(AMGrapy& G, char v)
{
	for (int i = 0; i < G.vexnum; i++)
	{
		if (G.vexs[i] == v)
		{
			return i;
		}
	}
}
//采用邻接矩阵表示法,创建无向图G
int CreateUDG_1(AMGrapy& G)
{
	int i, j, k;
	char v1, v2;
	scanf("%d %d", &G.vexnum, &G.arcnum);//输入总顶点数和总边数
	getchar();//获取'\n', 以免对之后字符的输入有影响
	for (i = 0; i < G.vexnum; i++)
	{
		scanf("%c", &G.vexs[i]);
	}

	for (i = 0; i < G.vexnum; i++)
	{
		for (j = 0; j < G.vexnum; j++)
		{
			G.arcs[i][j] = 0;
		}
	}

	for (k = 0; k < G.arcnum; k++)
	{
		getchar();
		scanf("%c%c", &v1, &v2);
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
		G.arcs[i][j] = G.arcs[j][i] = 1;
	}
	return 1;
}

void DFS_AM(AMGrapy& G, int v)
{
	cout << G.vexs[v] << " ";
	visited[v] = true;
	for (int i = 0; i < G.vexnum; i++)
	{
		if (G.arcs[v][i] && !visited[i])
		{
			DFS_AM(G, i);
		}
	}
}

int main()
{
	AMGrapy G;
	CreateUDG_1(G);
	int v = 0;
	DFS_AM(G, v);
	cout << endl;
	system("pause");
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qiahBwWo-1666313142247)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221021002240742.png)]

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VNtOrzpR-1666313142247)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221021082858656.png)]

返回目录

 

3.2使用邻接表表示图的深度优先搜索

思路

先访问根结点,边结点类指针指向任意一个与根结点相互连接的结点,并将它设置为当前结点,只要该结点没有访问过,就递归调用深度优先搜索算法,一直往深处递归,直到下一个结点为空,然后返回,访问其他结点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2FnUJiby-1666313142247)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221020231511387.png)]

 

代码实现
#include <iostream>
using namespace std;
#define MVNum 100
bool visited[MVNum] = { 0 };
// 边结点类
struct ArcNode
{
	int adjvex; //该条边所指向的顶点的下标
	ArcNode* nextarc; // 指向下一条边的指针
	int info;//与边相应的信息
};
//表头结点类
typedef struct VexNode
{
	char data; //顶点的数据
	ArcNode* firstarc;  //第一个指向的边结点的指针
}AdjList[MVNum];
//关联表图类
struct ALGrapy
{
	AdjList vertices;
	int vexnum, arcnum;
};
// 找到顶点对应下标
int LocateVex(ALGrapy& G, char v0)
{
	for (int i = 0; i < G.vexnum; i++)
	{
		if (v0 == G.vertices[i].data)
		{
			return i;
		}
	}
}

int CreateUDG_2(ALGrapy& G)
{
	int i, j, k;
	char v1, v2;
	scanf("%d %d", &G.vexnum, &G.arcnum);
	getchar();
	for (i = 0; i < G.vexnum; i++)//初始化存储表头结点的数组
	{
		scanf("%c", &G.vertices[i].data);
		G.vertices[i].firstarc = NULL;
	}

	for (k = 0; k < G.arcnum; k++)
	{
		getchar();
		scanf("%c%c", &v1, &v2);
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
		ArcNode* p1 = new ArcNode;
		p1->adjvex = j;
		p1->nextarc = G.vertices[i].firstarc;
		G.vertices[i].firstarc = p1;
		ArcNode* p2 = new ArcNode;
		p2->adjvex = i;
		p2->nextarc = G.vertices[j].firstarc;
		G.vertices[j].firstarc = p2;
	}
	return 1;
}
//递归清除一个表头的在堆区开辟的内存空间,先从最深处开始释放
void clearLine(ArcNode* arc)
{
	if (arc->nextarc)
	{
		clearLine(arc->nextarc);
	}
	delete arc;
}
//清除在堆区开辟的内存空间
void clearGrapy(ALGrapy& G)
{
	for (int i = 0; i < G.vexnum; i++)
	{
		if (G.vertices[i].firstarc)
		{
			clearLine(G.vertices[i].firstarc);
		}
	}
}

void DFS_AL(ALGrapy& G, int v)
{
	int m = 0;
	cout << G.vertices[v].data << " ";
	visited[v] = true;
	ArcNode* p;
	p = G.vertices[v].firstarc;
	while (p)
	{
		m = p->adjvex;
		if (!visited[m])
		{
			DFS_AL(G, m);
		}
		p = p->nextarc;
	}
}

int main()
{
	ALGrapy G;
	int v = 0;
	CreateUDG_2(G);
	DFS_AL(G, v);
	cout << endl;
	clearGrapy(G);
	system("pause");
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6X0W59Qs-1666313142248)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221021000433072.png)]

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f4aP7Pbc-1666313142248)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20221021000500693.png)]

返回目录

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值