图的遍历-DFS/BFS

图的遍历
调试版

// 基于C语言的图的遍历

#include <stdlib.h>
#include <stdio.h>

#define MAX_EDGE 15
#define MAX_SIZE 9
#define MAX_VERTEX 9

typedef int Edge; // 边
typedef char Vertex; // 顶点

// 定义图的存储结构 -- 邻接矩阵
typedef struct {
	int numV, numE;
	Edge edge[MAX_EDGE][MAX_EDGE];
	Vertex vertex[MAX_VERTEX];
}Graph;

int visited[MAX_VERTEX]; // 访问标记数组 - 未访问:非1, 已访问:1

// 创建图 - 基于邻接矩阵 - 初始化Graph中的变量
void create_graph(Graph *graph)
{
	int i, j;

	graph->numE = 15;
	graph->numV = 9;

	/* 读入顶点信息,建立顶点表 */
	graph->vertex[0] = 'A';
	graph->vertex[1] = 'B';
	graph->vertex[2] = 'C';
	graph->vertex[3] = 'D';
	graph->vertex[4] = 'E';
	graph->vertex[5] = 'F';
	graph->vertex[6] = 'G';
	graph->vertex[7] = 'H';
	graph->vertex[8] = 'I';


	for (i = 0; i < graph->numV; i++)/* 初始化图 */
	{
		for (j = 0; j < graph->numV; j++)
		{
			graph->edge[i][j] = 0;
		}
	}

	graph->edge[0][1] = 1;
	graph->edge[0][5] = 1;

	graph->edge[1][2] = 1;
	graph->edge[1][8] = 1;
	graph->edge[1][6] = 1;

	graph->edge[2][3] = 1;
	graph->edge[2][8] = 1;

	graph->edge[3][4] = 1;
	graph->edge[3][7] = 1;
	graph->edge[3][6] = 1;
	graph->edge[3][8] = 1;

	graph->edge[4][5] = 1;
	graph->edge[4][7] = 1;

	graph->edge[5][6] = 1;

	graph->edge[6][7] = 1;


	for (i = 0; i < graph->numV; i++)
	{
		for (j = i; j < graph->numV; j++)
		{
			graph->edge[j][i] = graph->edge[i][j];
		}
	}
}

// 访问一个vertex顶点
void visit(Graph graph, int index) 
{
	printf("%c ", graph.vertex[index]);
}


/******************** 深度遍历 ********************/

void dfs(Graph graph, int index)
{
	visited[index] = 1;
	visit(graph, index);

	for (int i = 0; i < graph.numV; i++)
		if (graph.edge[index][i] == 1 && !visited)
			dfs(graph, i);
}

// 邻接矩阵的DFS
void dfs_traverse(Graph graph)
{
	for (int i = 0; i < graph.numV; i++) // 初始化标记数组为未访问
		visited[i] = 0;
	for (int i = 0; i < graph.numV; i++) // 对图的各个连通分量调用DFS, 如果是连通图,则只会执行一次
		if (!visited[i]) // 根据标记数组,判定vertex是否已经被访问
			dfs(graph, i);
}

/******************** 广度遍历 ********************/

typedef struct
{
	int data[MAX_SIZE];
	int front;
	int rear; 
}Queue; // 循环队列结构

void create_queue(Queue *queue)
{
	queue->front = 0;
	queue->rear = 0;
}

int isEmpty(Queue queue)
{
	if (queue.front == queue.rear) // 队列是否为空
		return 1;
	return 0;
}

int isFull(Queue queue)
{
	if ((queue.rear + 1) % MAX_SIZE == queue.front)
		return 1;
	return 0;
}

// 入队操作 - 入队的是序列号,而非元素Vertex
void enqueue(Queue *queue, int index)
{
	if ((queue->rear + 1) % MAX_SIZE == queue->front) // 队列是否满了
	{
		printf("The queue is full.");
		return;
	}
	queue->data[queue->rear] = index; // 存储
	queue->rear = (queue->rear + 1) % MAX_SIZE; // rear指针后移
}

// 出队 
void dequeue(Queue* queue, int* index)
{
	if (queue->front == queue->rear) // 队列为空
		return;
	*index = queue->data[queue->front]; // 将队头元素出队并赋值给index
	queue->front = (queue->front + 1) % MAX_SIZE; // front指针后移
}

void print_queue(Graph graph, Queue queue)
{
	printf("queue:");
	int cursor = queue.front;
	while (!isEmpty(queue) && cursor != queue.rear)
	{
		printf(" %c ", graph.vertex[queue.data[cursor]]);
		cursor = (cursor + 1) % MAX_SIZE;
	}
	printf("\n");
}

// 访问某个顶点并入队
void bfs_visit_vertex(Graph graph, int j, Queue* queue)
{
	visited[j] = 1;
	//visit(graph, j);


	printf("入队前:%c  ", graph.vertex[j]);
	print_queue(graph, *queue);
	enqueue(queue, j);
	printf("入队后:");
	print_queue(graph, *queue);
	printf("\n");
}

void bfs_traverse(Graph graph)
{
	Queue queue;
	create_queue(&queue);

	for (int i = 0; i < graph.numV; i++)
		visited[i] = 0;

	for (int i = 0; i < graph.numV; i++) // 对每个连通分量做循环 
	{
		
		if (!visited[i]) 
		{
			printf("\n====>%d", i);
			bfs_visit_vertex(graph, i, &queue); //访问连通分量的第一个邻接点,并入队
			while (!isEmpty(queue))
			{
				printf("出队前:");
				print_queue(graph, queue);
				dequeue(&queue, &i); // 将队列中的第一个顶点(序列号)出队
				printf("出队后:");
				
				print_queue(graph, queue);
				printf("\n");
				for (int j = 0; j < graph.numV; j++) // 遍历出队的顶点的所有的邻接点,然后将邻接点全部入队
				{
					if (graph.edge[i][j] == 1 && !visited[j]) // 未访问过的邻接点
					{
						bfs_visit_vertex(graph, j, &queue);
					}
				}
			}
		}
	}
}


int main()
{
	Graph graph;
	create_graph(&graph);
	printf("\n深度遍历:");
	dfs_traverse(graph);
	printf("\n广度遍历:");
	bfs_traverse(graph);
	return 0;
}

最终版

// 基于C语言的图的遍历

#include <stdlib.h>
#include <stdio.h>

#define MAX_EDGE 15
#define MAX_SIZE 9
#define MAX_VERTEX 9

typedef int Edge; // 边
typedef char Vertex; // 顶点

// 定义图的存储结构 -- 邻接矩阵
typedef struct {
	int numV, numE;
	Edge edge[MAX_EDGE][MAX_EDGE];
	Vertex vertex[MAX_VERTEX];
}Graph;

int visited[MAX_VERTEX]; // 访问标记数组 - 未访问:非1, 已访问:1

// 创建图 - 基于邻接矩阵 - 初始化Graph中的变量
void create_graph(Graph *graph)
{
	int i, j;

	graph->numE = 15;
	graph->numV = 9;

	/* 读入顶点信息,建立顶点表 */
	graph->vertex[0] = 'A';
	graph->vertex[1] = 'B';
	graph->vertex[2] = 'C';
	graph->vertex[3] = 'D';
	graph->vertex[4] = 'E';
	graph->vertex[5] = 'F';
	graph->vertex[6] = 'G';
	graph->vertex[7] = 'H';
	graph->vertex[8] = 'I';


	for (i = 0; i < graph->numV; i++)/* 初始化图 */
	{
		for (j = 0; j < graph->numV; j++)
		{
			graph->edge[i][j] = 0;
		}
	}

	graph->edge[0][1] = 1;
	graph->edge[0][5] = 1;

	graph->edge[1][2] = 1;
	graph->edge[1][8] = 1;
	graph->edge[1][6] = 1;

	graph->edge[2][3] = 1;
	graph->edge[2][8] = 1;

	graph->edge[3][4] = 1;
	graph->edge[3][7] = 1;
	graph->edge[3][6] = 1;
	graph->edge[3][8] = 1;

	graph->edge[4][5] = 1;
	graph->edge[4][7] = 1;

	graph->edge[5][6] = 1;

	graph->edge[6][7] = 1;


	for (i = 0; i < graph->numV; i++)
	{
		for (j = i; j < graph->numV; j++)
		{
			graph->edge[j][i] = graph->edge[i][j];
		}
	}
}

// 访问一个vertex顶点
void visit(Graph graph, int index) 
{
	printf("%c ", graph.vertex[index]);
}


/******************** 深度遍历 ********************/

void dfs(Graph graph, int index)
{
	visited[index] = 1;
	visit(graph, index);

	for (int i = 0; i < graph.numV; i++)
		if (graph.edge[index][i] == 1 && !visited)
			dfs(graph, i);
}

// 邻接矩阵的DFS
void dfs_traverse(Graph graph)
{
	for (int i = 0; i < graph.numV; i++) // 初始化标记数组为未访问
		visited[i] = 0;
	for (int i = 0; i < graph.numV; i++) // 对图的各个连通分量调用DFS, 如果是连通图,则只会执行一次
		if (!visited[i]) // 根据标记数组,判定vertex是否已经被访问
			dfs(graph, i);
}

/******************** 广度遍历 ********************/

typedef struct
{
	int data[MAX_SIZE];
	int front;
	int rear; 
}Queue; // 循环队列结构

void create_queue(Queue *queue)
{
	queue->front = 0;
	queue->rear = 0;
}

int isEmpty(Queue queue)
{
	if (queue.front == queue.rear) // 队列是否为空
		return 1;
	return 0;
}

int isFull(Queue queue)
{
	if ((queue.rear + 1) % MAX_SIZE == queue.front)
		return 1;
	return 0;
}

// 入队操作 - 入队的是序列号,而非元素Vertex
void enqueue(Queue *queue, int index)
{
	if ((queue->rear + 1) % MAX_SIZE == queue->front) // 队列是否满了
	{
		printf("The queue is full.");
		return;
	}
	queue->data[queue->rear] = index; // 存储
	queue->rear = (queue->rear + 1) % MAX_SIZE; // rear指针后移
}

// 出队 
void dequeue(Queue* queue, int* index)
{
	if (queue->front == queue->rear) // 队列为空
		return;
	*index = queue->data[queue->front]; // 将队头元素出队并赋值给index
	queue->front = (queue->front + 1) % MAX_SIZE; // front指针后移
}

void bfs_traverse(Graph graph)
{
	Queue queue;
	create_queue(&queue);

	for (int i = 0; i < graph.numV; i++)
		visited[i] = 0;

	for (int i = 0; i < graph.numV; i++) // 对每个顶点做循环 
	{
		
		if (!visited[i]) 
		{
			/*printf("\n====>%d", i);*/
			visited[i] = 1;
			visit(graph, i);
			enqueue(&queue, i);
			while (!isEmpty(queue))
			{
				dequeue(&queue, &i);
				for (int j = 0; j < graph.numV; j++)
				{
					if (graph.edge[i][j] == 1 && !visited[j])
					{
						visited[j] = 1;			 
						visit(graph, j);
						enqueue(&queue, j);				 
					}
				}
			}
		}
	}
}

int main()
{
	Graph graph;
	create_graph(&graph);
	printf("\n深度遍历:");
	dfs_traverse(graph);
	printf("\n广度遍历:");
	bfs_traverse(graph);
	return 0;
}
posted @ 2020-11-26 17:53  墨狮  阅读(68)  评论(0编辑  收藏  举报