广度优先搜索(BFS)和深度优先搜索(DFS)
目录
一、邻接矩阵和邻接表
1.1邻接矩阵创建图
1.2邻接表创建图
二、广度优先搜索
2.1使用邻接矩阵表示图的广度优先搜索
2.2使用邻接表表示图的广度优先搜索
2.3非连通图的广度优先搜索
三、深度优先搜索
3.1使用邻接矩阵表示图的深度优先搜索
3.2使用邻接表表示图的深度优先搜索
一、邻接矩阵和邻接表
1.1邻接矩阵
思路
图的邻接矩阵存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息。
代码实现
#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指针中,然后把该指针设置为表头元素的第一条边
代码实现
#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,然后再把它推入队列中,依次出队列,然后找到与它相连的结点并且没有被访问过的结点,然后将其访问并把它推入队列,直到队列为空说明所有的结点访问完毕
代码实现
#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;
}
运行结果:
返回目录
2.2使用邻接表表示图的广度优先搜索
思路
准备一个字符队列存放已经访问过的结点,首先将起点先访问,并且将是否访问的数组置为1,然后再把它推入队列中,依次出队列,然后找到与它相连的结点并且没有被访问过的结点,然后将其访问并把它推入队列,直到队列为空说明所有的结点访问完毕
代码实现
#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;
}
运行结果:
返回目录
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;
}
运行结果:
返回目录
三、深度优先搜索
3.1使用邻接矩阵表示图的深度优先搜索
思路
首先访问根结点,然后找出与根结点相连且没有被访问过的结点,然后对它递归调用深度优先搜索,直到平凡的情况与结点不相连接,回溯至上一级调用,直到一直回溯到对根结点的调用,即深度优先搜索完成
代码实现
#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;
}
运行结果:
返回目录
3.2使用邻接表表示图的深度优先搜索
思路
先访问根结点,边结点类指针指向任意一个与根结点相互连接的结点,并将它设置为当前结点,只要该结点没有访问过,就递归调用深度优先搜索算法,一直往深处递归,直到下一个结点为空,然后返回,访问其他结点
代码实现
#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;
}
运行结果: