/* 看了其他大神关于这题的代码,都是自己写的,有的地方对于我这个初学数据结构的小白来说有点难理解,我这个主要是MOOC 浙大数据结构 课后所给的代码 修改 完成的,不懂的地方还可以去MOOC看网课理解哈哈。*/
给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。
输入格式:
输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。
输出格式:
按照”{ v1v2…vk}”的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。
输入样例:
- 8 6
- 0 7
- 0 1
- 2 0
- 4 1
- 2 4
- 3 5`
输出样例:
- { 0 1 4 2 7 }
- { 3 5 }
- { 6 }
- { 0 1 2 7 4 }
- { 3 5 }
- { 6 }
/* 参考资料
1 中国大学MOOC 浙大 数据结构 第六讲 图(上)
2 DFS
作者:拉风小宇
来源:优快云
原文:https://blog.youkuaiyun.com/lafengxiaoyu/article/details/53493080
版权声明:本文为博主原创文章,转载请附上博文链接!
3 BFS
作者:拉风小宇
来源:优快云
原文:https://blog.youkuaiyun.com/lafengxiaoyu/article/details/53502873
版权声明:本文为博主原创文章,转载请附上博文链接!*/
#include <stdio.h>
#include <stdlib.h>
/* 图的邻接矩阵表示法 */
#define MaxVertexNum 100 /* 最大顶点数设为100 */
#define INFINITY 65535 /* ∞设为双字节无符号整数的最大值65535*/
int Visited[MaxVertexNum];/* 标记V已访问 */
#define ERROR 0
typedef int Vertex; /* 用顶点下标表示顶点,为整型 */
typedef int WeightType; /* 边的权值设为整型 */
//typedef char DataType; /* 顶点存储的数据类型设为字符型 */
typedef int ElementType;
typedef int Position;
/* 边的定义 */
typedef struct ENode *PtrToENode;
struct ENode{
Vertex V1, V2; /* 有向边<V1, V2> */
WeightType Weight; /* 权重 */
};
typedef PtrToENode Edge;
/* 图结点的定义 */
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; /* 顶点数 */
int Ne; /* 边数 */
WeightType G[MaxVertexNum][MaxVertexNum]; /* 邻接矩阵 */
//DataType Data[MaxVertexNum]; /* 存顶点的数据 */
/* 注意:很多情况下,顶点无数据,此时Data[]可以不用出现 */
};
typedef PtrToGNode MGraph; /* 以邻接矩阵存储的图类型 */
struct Node {
int Data;
struct Node *Next;
};
struct QNode {
struct Node *rear;
struct Node *front;
};
typedef struct QNode *Queue;
MGraph CreateGraph( int VertexNum );
void InsertEdge( MGraph Graph, Edge E );
MGraph BuildGraph();
void Visit(Vertex V);
int IsEmpty(Queue Q);
Queue CreateQueue();
int DeleteQ(Queue PtrQ);
void InsertQ(int item, Queue PtrQ);
bool IsEdge(MGraph Graph, Vertex V, Vertex W);
void BFS(MGraph Graph, Vertex S, void(*Visit)(Vertex));
void ListComponentsBFS(MGraph Graph);
void DFS(MGraph Graph, Vertex V, void(*Visit)(Vertex));
void ListComponentsDFS(MGraph Graph);
int main()
{
MGraph Graph;
Graph = BuildGraph();
for (int i = 0; i < MaxVertexNum; i++) {
Visited[i] = false;
}
//printf("下面执行DFS\n");
ListComponentsDFS( Graph );
/* 在执行完 ListComponentsDFS( Graph ); 后,需重置 Visited[i]
否则 ListComponentsBFS( Graph ); 执行不了。。。 */
for (int i = 0; i < MaxVertexNum; i++) {
Visited[i] = false;
}
//printf("下面执行BFS\n");
ListComponentsBFS( Graph );
return 0;
}
MGraph CreateGraph( int VertexNum )
{ /* 初始化一个有VertexNum个顶点但没有边的图 */
Vertex V, W;
MGraph Graph;
Graph = (MGraph)malloc(sizeof(struct GNode)); /* 建立图 */
Graph->Nv = VertexNum;
Graph->Ne = 0;
/* 初始化邻接矩阵 */
/* 注意:这里默认顶点编号从0开始,到(Graph->Nv - 1) */
for (V=0; V<Graph->Nv; V++)
for (W=0; W<Graph->Nv; W++)
Graph->G[V][W] = INFINITY;
//printf("图初始化完成\n");
return Graph;
}
void InsertEdge( MGraph Graph, Edge E )
{
/* 插入边 <V1, V2> */
Graph->G[E->V1][E->V2] = E->Weight;
/* 若是无向图,还要插入边<V2, V1> */
Graph->G[E->V2][E->V1] = E->Weight;
}
MGraph BuildGraph()
{
MGraph Graph;
Edge E;
Vertex V;
int Nv, Ne, i;
//printf("输入顶点数\n");
scanf("%d %d", &Nv, &Ne); /* 读入顶点个数 */
Graph = CreateGraph(Nv); /* 初始化有Nv个顶点但没有边的图 */
Graph->Ne = Ne;
//printf("输入边数\n");
//scanf("%d", &(Graph->Ne)); /* 读入边数 */
if ( Graph->Ne != 0 ) { /* 如果有边 */
E = (Edge)malloc(sizeof(struct ENode)); /* 建立边结点 */
/* 读入边,格式为"起点 终点 权重",插入邻接矩阵 */
for (i=0; i<Graph->Ne; i++) {
//printf("输入一条边的两个端点\n");
scanf("%d %d", &E->V1, &E->V2);
E->Weight = 1;
/* 注意:如果权重不是整型,Weight的读入格式要改 */
InsertEdge( Graph, E );
}
}
/* 如果顶点有数据的话,读入数据 */
//for (V=0; V<Graph->Nv; V++)
// scanf(" %c", &(Graph->Data[V]));
//printf("图建立完成\n");
return Graph;
}
void Visit(Vertex V)
{
printf("正在访问顶点%d\n", V + 1);
}
int IsEmpty(Queue Q) {
return(Q->front == NULL);
};
Queue CreateQueue() {
Queue PtrQ;
PtrQ = (Queue)malloc(sizeof(struct QNode));
struct Node *rear;
struct Node *front;
rear = (Node*)malloc(sizeof(struct Node));
rear = NULL;
front = (Node*)malloc(sizeof(struct Node));
front = NULL;
PtrQ->front = front;
PtrQ->rear = rear;
return PtrQ;
};
int DeleteQ(Queue PtrQ) {
struct Node *FrontCell;
int FrontElem;
if (IsEmpty(PtrQ)) {
printf("队列空");
return ERROR;
}
FrontCell = PtrQ->front;
if (PtrQ->front == PtrQ->rear)
PtrQ->front = PtrQ->rear = NULL;
else {
PtrQ->front = PtrQ->front->Next;
}
FrontElem = FrontCell->Data;
free(FrontCell);
return FrontElem;
}
void InsertQ(int item, Queue PtrQ) {
struct Node *FrontCell;
FrontCell = (Node*)malloc(sizeof(struct Node));
FrontCell->Data = item;
FrontCell->Next = NULL;
if (IsEmpty(PtrQ)) {
PtrQ->front = FrontCell;
PtrQ->rear = FrontCell;
}
else {
PtrQ->rear->Next = FrontCell;
PtrQ->rear = FrontCell;
}
};
/* 邻接矩阵存储的图 - BFS */
/* IsEdge(Graph, V, W)检查<V, W>是否图Graph中的一条边,即W是否V的邻接点。 */
/* 此函数根据图的不同类型要做不同的实现,关键取决于对不存在的边的表示方法。*/
/* 例如对有权图, 如果不存在的边被初始化为INFINITY, 则函数实现如下: */
bool IsEdge(MGraph Graph, Vertex V, Vertex W)
{
return Graph->G[V][W]<INFINITY ? true : false;
}
/* Visited[]为全局变量,已经初始化为false
在main函数中执行 */
void BFS(MGraph Graph, Vertex S, void(*Visit)(Vertex))
{ /* 以S为出发点对邻接矩阵存储的图Graph进行BFS搜索 */
Queue Q;
Vertex V, W;
Q = CreateQueue(); /* 创建空队列, MaxSize为外部定义的常数 */
/* 访问顶点S:此处可根据具体访问需要改写 */
//Visit(S);
Visited[S] = true; /* 标记S已访问 */
InsertQ(S, Q); /* S入队列 */
printf("{");
while (!IsEmpty(Q)) {
V = DeleteQ(Q); /* 弹出V */
printf(" %d", V);
for (W = 0; W<Graph->Nv; W++) /* 对图中的每个顶点W */
/* 若W是V的邻接点并且未访问过 */
if (!Visited[W] && IsEdge(Graph, V, W)) {
/* 访问顶点W */
//Visit(W);
Visited[W] = true; /* 标记W已访问 */
InsertQ(W, Q); /* W入队列 */
}
} /* while结束*/
printf(" }\n");
}
void ListComponentsBFS(MGraph Graph)
{
int V;
for (V=0; V<Graph->Nv; V++) {
if (!Visited[V]) {
BFS(Graph, V, Visit);
}
}
}
void DFS(MGraph Graph, Vertex V, void(*Visit)(Vertex))
{ /* 以V为出发点对邻接表存储的图Graph进行DFS搜索 */
Vertex W;
//Visit(V); /* 访问第V个顶点 */
Visited[V] = true; /* 标记V已访问 */
printf(" %d", V);
for (W = 0; W<Graph->Nv;W++ ) /* 对V的每个邻接点W */
if ((!Visited[W])&&(Graph->G[V][W]==1)) /* 若未被访问 */
DFS(Graph, W, Visit); /* 则递归访问之 */
}
void ListComponentsDFS(MGraph Graph)
{
int V;
for (V=0; V<Graph->Nv; V++) {
if (!Visited[V]) {
printf("{");
DFS(Graph, V, Visit);
printf(" }\n");
}
}
}