这个代码是在图的邻接矩阵(无项、有权)的代码的基础上,添加了DFS和BFS两个函数,DFS是深度优先遍历图,BFS是广度优先遍历图,并且修改主函数代码,图的邻接矩阵(无项、有权)的代码具体请查看 【C语言\数据结构】图之邻接矩阵(无向、有权)代码简单实现,这里就不过多赘述。
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顶点还没有被访问过。
下面是一个例子,以及这个例子对应的递归图,红色的箭头一直往深处走,走到底从粉色的箭头递归回来。
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
#include
#include
#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判断顶点是否被访问过。
最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。
同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。
谢谢您的支持,期待与您在下一篇文章中再次相遇!