本小结使用C完成了图的深度优先搜索和广度优先搜索的Demo
输入样例都是无向图,并且节点使用整数表示
DFS和BFS时使用的都是上述邻接矩阵存储的图
(一)图
可以使用邻接矩阵或者邻接表存储图
(0)定义
- 对于无向图
- w为0:表示顶点重合
- w为∞:表示顶点之间没有边
- w为1:表示顶点之间有一条边
- 对于有向图
- w为n:表示顶点之间距离/权值为n(为0时表示两点重合)
- w为-1:表示顶点之间没有边
(1)邻接矩阵存储
- 使用二维数组存储矩阵
- 矩阵中的第i行第j列表示图的顶点i到顶点j之间的距离:对于无向图来说,1表示有连接,∞表示没有连接,0表示i和j是相同的点(距离为0)
- 二维数组是沿对角线对称的:因为顶点i到顶点j的距离==顶点j到顶点i的距离
- 使用C实现
- main.c:
#include <stdio.h>
#include <stdlib.h>
#include "method.c"
int main() {
AdjMatrix G;
CreateGraph(&G);
PrintGraph(&G);
//DFSTraverse(&G);
//BFSTraverse(&G);
system("pause");
return 0;
}
- method.c
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "include.h"
#include "include.h"
#define true 1
#define false 0
//创建无向图
void CreateGraph(AdjMatrix *G){
int n,e;
int vi,vj,w,i,j;
printf("请输入图的顶点数和边数:");
scanf("%d%d",&n,&e);
G->numV = n;
G->numE = e;
//初始化图
for(i=0;i < n; i++){
for(j=0; j < n; j++){
if(i == j)
G->Edge[i][j] = 0;
else
G->Edge[i][j] = INT_MAX;
}
}
//存放顶点
for(i=0;i < n; i++){
printf("请输入%d个顶点的信息",i+1);
scanf("%d",&G->Vertices[i]);
}
printf("\n");
for(int i=0; i < e; i++){
printf("请输入边的信息i,j,w(用空分隔)");
scanf("%d%d%d",&vi,&vj,&w);
G->Edge[vi-1][vj-1] = w;
G->Edge[vj-1][vi-1] = w;
}
}
//打印无向图
void PrintGraph(AdjMatrix *G){
int i,j;
printf("\n输出顶点的信息:\n");
for(i=0; i < G->numV; i++){
printf("%8d",G->Vertices[i]);
}
printf("\n输出邻接矩阵\n");
printf("\t");
for(i=0; i < G->numV; i++){
printf("%8d",G->Vertices[i]);
}
for(i=0; i < G->numV; i++){
printf("\n%8d",i+1);
for(j=0; j < G->numV; j++){
if(G->Edge[i][j] == INT_MAX)
printf("%8s","∞");
else
printf("%8d",G->Edge[i][j]);
}
printf("\n");
}
}
- include.h
#include <stdio.h>
#include <stdlib.h>
#define MaxVertices 100 //最大顶点数
typedef struct{ //定义邻接矩阵结构体
int Vertices[MaxVertices]; //顶点数组
int Edge[MaxVertices][MaxVertices]; //边的数组
int numV; //vertices
int numE; //edges
}AdjMatrix;
- 测试数据
5 7
1 2 3 4 5
1 3 1
1 5 1
2 3 1
2 4 1
2 5 1
3 5 1
4 5 1
(一)深度优先搜索
深度优先搜索和广度优先搜索使用的都是回溯的思想
- 深度优先搜索Deepth First Search
- 构造一个标记数组visited,判定节点是否被访问过
- 首先从图的初始节点开始,如果节点没有被访问过,对该节点进行单点DFS
- 对于单点,首先标记数组visited,然后对于该点的相邻点,如果没有被访问过,则递归进行DFS
- 对于一个点,如果该点的所有相邻节点都被访问过,那么会回溯到递归的上一层
//单点DFS
void DFS(AdjMatrix *G, int k, int* vi){
vi[k] = true;
printf("目前正在访问的节点是:%d\n",G->Vertices[k]);
for(int i=0; i < G->numV; i++){
if(G->Edge[k][i] == 1 && !vi[i])
DFS(G,i,vi);
}
}
//深度优先搜索图
void DFSTraverse(AdjMatrix *G){
int visited[G->numV];
for(int i=0; i < G->numV; i++){
visited[i] = false;
}
printf("\n");
for(int i=0; i < G->numV; i++){
if(!visited[i]){
DFS(G,i,visited);
}
}
}
(二)广度优先搜素
- 广度优先搜索Breadth First Search
- 也需要一个visited标记数组
- 使用队列存储当前访问的顶点:对于一个顶点A,首先让A入队同时访问A节点;
- 如果队列不为空,那么取出队首元素B,找到所有和B相邻并且没有被访问过的节点,以此访问并入队
void BFSTraverse(AdjMatrix *G){
int visited[G->numV];
for(int i=0; i < G->numV; i++){ //初始化标记数组
visited[i] = false;
}
int queue[G->numV]; //使用数组表示简单队列
int rear = -1; //队列尾
int front = -1; //队列首
//核心算法
for(int i=0; i < G->numV; i++){
if(!visited[i]){
visited[i] = true;
printf("正在访问的节点是%d:\n",G->Vertices[i]);
queue[++rear] = i;
}
while(front != rear){
int k = queue[front];
front++;
for(int j=0; j < G->numV; j++){
if(G->Edge[k][j] == 1 && !visited[j]){
visited[j] = true;
printf("正在访问的节点是%d:\n",G->Vertices[j]);
queue[++rear] = j;
}
}
}
}
}
- 测试样例
7 7
1 2 3 4 5 6 7
1 2 1
2 3 1
3 4 1
1 5 1
1 6 1
5 6 1
5 7 1
输出:
正在访问的节点是1:
正在访问的节点是3:
正在访问的节点是4:
正在访问的节点是6:
正在访问的节点是2:
正在访问的节点是7:
正在访问的节点是5: