06-图1 列出连通集 (25分)
题目描述
给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。
输入格式:
输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。
输出格式:
按照"{v1 v2 ... 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 }
解题思路
首先选择用什么方式表示图,邻接矩阵还是邻接表。根据题意:按编号递增的顺序访问邻接点
,如果用邻接表的话插入的时候就很麻烦,因为需要额外的判断来保证递增顺序,所以我选择了用邻接矩阵表示图。那么可以先根据输入构建邻接矩阵,然后再对矩阵DFS和BFS。对于DFS,每遇到一个未访问邻接点就递归;对于BFS,和二叉树的层次遍历类似,借助于队列实现,每遇到一个未访问邻接点就入队。
代码
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 10
struct Graph {
int vertexCount; //顶点数
int edgeCount; //边数
int matrix[MAXSIZE][MAXSIZE]; //用邻接矩阵表示图
};
typedef struct Graph *MGraph;
//用链表表示队列
struct QNode {
int data;
struct QNode *next;
};
typedef struct QNode *Queue;
int visited[MAXSIZE] = {0}; //判断结点是否访问过
MGraph createGraph(int N, int M);
void listConnectedSet_DFS(MGraph graph);
void listConnectedSet_BFS(MGraph graph);
void DFS(MGraph graph, int index);
void BFS(MGraph graph, int index);
Queue createQueue();
void pushQueue(Queue queue, int index);
int popQueue(Queue queue);
int isEmpty(Queue queue);
int main() {
int N, M;
scanf("%d %d", &N, &M);
MGraph graph = createGraph(N, M);
listConnectedSet_DFS(graph);
for (int i = 0; i < N; i++) { //重置访问数组
visited[i] = 0;
}
listConnectedSet_BFS(graph);
return 0;
}
//创建无向图
MGraph createGraph(int N, int M) {
MGraph graph = (MGraph) malloc(sizeof(struct Graph));
graph->vertexCount = N;
graph->edgeCount = M;
for (int i = 0; i < MAXSIZE; i++) {
for (int j = 0; j < MAXSIZE; j++) {
graph->matrix[i][j] = 0;
}
}
for (int i = 0; i < M; i++) {
int v1, v2;
scanf("%d %d", &v1, &v2);
graph->matrix[v1][v2] = 1;
graph->matrix[v2][v1] = 1;
}
return graph;
}
//对整个图DFS
void listConnectedSet_DFS(MGraph graph) {
for (int i = 0; i < graph->vertexCount; i++) {
if (!visited[i]) {
printf("{");
DFS(graph, i);
printf(" }\n");
}
}
}
//对整个图BFS
void listConnectedSet_BFS(MGraph graph) {
for (int i = 0; i < graph->vertexCount; i++) {
if (!visited[i]) {
printf("{");
BFS(graph, i);
printf(" }\n");
}
}
}
//对一个连通集DFS
void DFS(MGraph graph, int index) {
visited[index] = 1;
printf(" %d", index);
for (int i = 0; i < graph->vertexCount; i++) {
if (graph->matrix[index][i] == 1 && !visited[i]) {
DFS(graph, i);
}
}
}
//对一个连通集BFS
void BFS(MGraph graph, int index) {
Queue queue = createQueue();
pushQueue(queue, index);
visited[index] = 1;
printf(" %d", index);
while (!isEmpty(queue)) {
int index = popQueue(queue);
for (int i = 0; i < graph->vertexCount; i++) {
if (graph->matrix[index][i] == 1 && !visited[i]) {
pushQueue(queue, i);
printf(" %d", i);
visited[i] = 1;
}
}
}
}
//新建队列,返回哨兵结点
Queue createQueue() {
Queue queue = (Queue) malloc(sizeof(struct QNode));
queue->data = -1; queue->next = NULL;
return queue;
}
//尾插法入队
void pushQueue(Queue queue, int index) {
Queue rear = queue;
while (rear->next) rear = rear->next;
Queue node = (Queue) malloc(sizeof(struct QNode));
node->data = index; node->next = NULL;
rear->next = node;
}
//删除首结点
int popQueue(Queue queue) {
if (!queue->next) return -1;
Queue target = queue->next;
int ret = target->data;
queue->next = target->next;
free(target);
return ret;
}
//判断队列是否为空
int isEmpty(Queue queue) {
return queue->next == NULL;
}