广度优先搜索(BFS)寻找迷宫两点之间最短路径的C语言实现

一、问题描述

根据输入的长和宽随机生成一个迷宫,随机生成或者输入一个起点和一个终点,运用广度优先搜索算法,找到这个迷宫中起点到终点的最短路径,并输出结果。

二、思路与算法

1.根据给定的迷宫长和宽创建一个动态数组,初始化数组并随机生成一个迷宫,再随机生成或者输入一个起点和一个终点。

2.设置一个结构体Node,其中包括点的坐标,以及五个指针:front(用于后期回溯得出的最短路径)、left、right、up、down。将起点和终点存入Node,从起点开始分别遍历其上下左右四个坐标是否有“墙”,若没有,向所查询的方向前进一步,新建一个Node,存入该点。

3.另设置一个结构体Queue,每前进一步,将新的点的指针存入Queue组成的链表,从头到尾遍历这个链表,链表中每个指针所指向的点都会重复步骤2。

4.重复2、3步骤,遍历整个树,以此实现广度搜索算法,直至找到终点。

5.如果找到了终点,则从已存好的终点Node开始,通过指针front一步步还原这个路径,直至走到起点,然后输出这个过程得到最终的最短路径。如果没有找到,则输出“No path.”。

三、C语言实现

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <Windows.h>

typedef struct Point
{
	int arrrow;
	int arrcol;
}Point;

typedef struct Node
{
	Point point;
	struct Node* front;
	struct Node* left;
	struct Node* right;
	struct Node* up;
	struct Node* down;
}Node;

typedef struct Queue
{
	struct Node* node;
	struct Queue* next;
};

struct Node* CreateNode(int row, int col)//长长的链表捏
{
	struct Node* node = (struct Node*)malloc(sizeof(struct Node));
	node->point.arrrow = row;
	node->point.arrcol = col;
	node->front = NULL;
	node->left = NULL;
	node->right = NULL;
	node->up = NULL;
	node->down = NULL;
	return node;
}

struct Queue* CreateQueue(struct Node* addnode)//动态队列记录每层搜索
{
	struct Queue* queue = (struct Queue*)malloc(sizeof(struct Queue));
	queue->node = addnode;
	queue->next = NULL;
	return queue;
}

//设置颜色的捏
VOID SetColor(UINT uFore, UINT uBack)
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTextAttribute(handle, uFore + uBack * 0x10);
}

//测试,打印全部迷宫
void TextPrint(char** maze, int mazerow, int mazecol)
{
	for (int i = 0; i < mazerow; i++)
	{
		for (int j = 0; j < mazecol; j++)
		{
			printf("%c", maze[i][j]);
		}
		printf("\n");
	}
	printf("\n");
}

//打印整个迷宫捏
void PrintMaze(char** maze, int mazerow, int mazecol)
{
	for (int i = 0; i < mazerow; i++)
	{
		for (int j = 0; j < mazecol; j++)
		{
			if (maze[i][j] == '=')
				printf(" ");
			else if (maze[i][j] == '1')
				printf("   ");
			else if (maze[i][j] == '0')
				printf("   ");
			else if (maze[i][j] == '-')
				printf("---");
			else if (maze[i][j] == ' ')
				printf("   ");
			else if (maze[i][j] == '!')
			{
				SetColor(4, 0);
				printf(" ! ");
				SetColor(7, 0);
			}
			else if (maze[i][j] == '<' || maze[i][j] == '>')
			{
				SetColor(4, 0);
				printf("%c", maze[i][j]);
				SetColor(7, 0);
			}
			else if (maze[i][j] == '*')
			{
				SetColor(4, 0);
				printf(" * ");
				SetColor(7, 0);
			}
			else
				printf("%c", maze[i][j]);
		}
		printf("\n");
	}
	printf("\n");
}

//初始化迷宫
void InitMaze(char **maze, int mazerow, int mazecol)
{
	//初始
	for (int i = 0; i < mazerow; i++)
	{
		for (int j = 0; j < mazecol; j++)
		{
			maze[i][j] = ' ';
		}
	}

	//拐角
	for (int i = 0; i < mazerow; i += 2)
	{
		for (int j = 0; j < mazecol; j += 2)
		{
			maze[i][j] = '+';
		}
	}

	//左右墙壁
	for (int i = 1; i < mazerow; i += 2)
	{
		maze[i][0] = '|';
		maze[i][mazecol - 1] = '|';
	}

	//上下墙壁
	for (int i = 1; i < mazecol; i += 2)
	{
		maze[0][i] = '-';
		maze[mazerow - 1][i] = '-';
	}

}

//随机生成迷宫
void CreateMaze(char **maze, int mazerow, int mazecol, int wallweight)
{
	srand((unsigned)time(NULL));
	for (int i = 1; i < mazerow; i += 2)
	{
		for (int j = 2; j < mazecol - 2; j += 2)
		{
			int randnum = rand() % 10 + 1;
			if (randnum <= wallweight)
			{
				maze[i][j] = '|';
			}
			else
				maze[i][j] = '=';//原本所有通路都是1,为了打印时的美观性,将上下与左右区分
		}
	}
	for (int i = 1; i < mazecol; i += 2)
	{
		for (int j = 2; j < mazerow - 2; j += 2)
		{
			int randnum = rand() % 10 + 1;
			if (randnum <= wallweight)
			{
				maze[j][i] = '-';
			}
			else
				maze[j][i] = '1';
		}
	}
	PrintMaze(maze, mazerow, mazecol);
}

//设置起点和终点
Point StartAndEnd(char** maze, int row, int col)
{
	/*srand((unsigned)time(NULL)); */
	Point point;
	int randomrow = rand() % row + 1;
	int randomcol = rand() % col + 1;
	printf("[%d, %d]\n", randomrow, randomcol);
	point.arrrow = randomrow * 2 - 1;
	point.arrcol = randomcol * 2 - 1;
	return point;
}

//广度优先算法
int BFS(char** maze, Point start, Point end, int mazerow, int mazecol)
{
	int row = start.arrrow;
	int col = start.arrcol;
	struct Node* startnode = CreateNode(row, col);//startnode不能动
	row = end.arrrow;
	col = end.arrcol;
	struct Node* endnode = CreateNode(row, col);
	struct Node* tmpnode = startnode;
	struct Queue* headqueue = CreateQueue(startnode);
	struct Queue* head = headqueue;//便于释放内存
	struct Queue* tmpqueue = headqueue;
	int flag = 0;

	//广度搜索遍历
	while (1)
	{
		row = headqueue->node->point.arrrow;
		col = headqueue->node->point.arrcol;
		tmpnode = headqueue->node;
		maze[row][col] = '0';
		if (maze[row][col - 1] == '=' && maze[row][col - 2] != '0')
		{
			struct Node* node = CreateNode(row, col - 2);
			node->front = tmpnode;
			tmpnode->left = node;
			maze[row][col - 2] = '0';
			if (row == end.arrrow && col - 2 == end.arrcol)
			{
				flag = 1;
				endnode = node;
				printf("found\n");
				break;
			}
			struct Queue* queue = CreateQueue(node);
			tmpqueue->next = queue;
			tmpqueue = queue;
		}
		if (maze[row][col + 1] == '=' && maze[row][col + 2] != '0')
		{
			struct Node* node = CreateNode(row, col + 2);
			node->front = tmpnode;
			tmpnode->right= node;
			maze[row][col + 2] = '0';
			if (row == end.arrrow && col + 2 == end.arrcol)
			{
				flag = 1;
				endnode = node;
				printf("found\n");
				break;
			}
			struct Queue* queue = CreateQueue(node);
			tmpqueue->next = queue;
			tmpqueue = queue;
		}
		if (maze[row - 1][col] == '1' && maze[row - 2][col] != '0')
		{
			struct Node* node = CreateNode(row - 2, col);
			node->front = tmpnode;
			tmpnode->up = node;
			maze[row - 2][col] = '0';
			if (row - 2 == end.arrrow && col == end.arrcol)
			{
				flag = 1;
				endnode = node;
				printf("found\n");
				break;
			}
			struct Queue* queue = CreateQueue(node);
			tmpqueue->next = queue;
			tmpqueue = queue;
		}
		if (maze[row + 1][col] == '1' && maze[row + 2][col] != '0')
		{
			struct Node* node = CreateNode(row + 2, col);
			node->front = tmpnode;
			tmpnode->down = node;
			maze[row + 2][col] = '0';
			if (row + 2 == end.arrrow && col == end.arrcol)
			{
				flag = 1;
				endnode = node;
				printf("found\n");
				break;
			}
			struct Queue* queue = CreateQueue(node);
			tmpqueue->next = queue;
			tmpqueue = queue;
		}
		if (headqueue->next == NULL)
		{
			flag = 0;
			printf("No path...\n");
			break;
		}
		headqueue = headqueue->next;
	}
	
	//如果找到,回溯路线
	if (flag)
	{
		//测试
		TextPrint(maze, mazerow, mazecol);

		flag = 0;

		tmpnode = endnode;
		while (1)
		{
			row = tmpnode->point.arrrow;
			col = tmpnode->point.arrcol;
			maze[row][col] = '*';
			tmpnode = tmpnode->front;
			if (tmpnode == NULL)
				break;
			if (tmpnode->left == endnode)
			{
				maze[row][col + 1] = '<';
			}
			else if (tmpnode->right == endnode)
			{
				maze[row][col - 1] = '>';
			}
			else if (tmpnode->up == endnode)
			{
				maze[row + 1][col] = '!';
			}
			else if (tmpnode->down == endnode)
			{
				maze[row - 1][col] = '!';
			}
			endnode = endnode->front;

			flag++;
		}
	}
	tmpqueue = head;
	while (tmpqueue != NULL)
	{
		tmpqueue = tmpqueue->next;
		free(head->node);
		free(head);
		head = tmpqueue;
	}
	return flag;
}

int main()
{
	//输入行和列
	int row = 0, col = 0;
	printf("please input row(行)and col(列):\n");
	scanf("%d %d", &row, &col);
	
	if (!(row > 0 && col > 0))
	{
		printf("input ERROR\n");
		return 1;
	}

	int wallweight = 0;
	printf("please input the weight of wall(1 ~ 10, less than 4 best):\n");
	scanf("%d", &wallweight);

	if (!(wallweight > 0 && wallweight <= 10))
	{
		printf("input ERROR\n");
		return 1;
	}

	//创建一个动态数组
	int mazerow = row * 2 + 1;
	int mazecol = col * 2 + 1;
	char **maze = (char**)calloc(mazerow, sizeof(char*));

	if (maze == NULL)
	{
		printf("malloc ERROR\n");
		return 1;
	}
	for (int i = 0; i < mazerow; i++)
	{
		maze[i] = (char*)calloc(mazecol, sizeof(char));

		if (maze[i] == NULL)
		{
			printf("malloc ERROR\n");
			return 1;
		}
	}

	//初始化迷宫
	InitMaze(maze, mazerow, mazecol);

	//随机生成迷宫
	int x = 0;
	do
	{
		CreateMaze(maze, mazerow, mazecol, wallweight);
		printf("Reset the maze? Yes(1)/No(0)\n");
		scanf("%d", &x);
	} while (x);

	//设置起点和终点
	int choice = 0;
	Point start;
	Point end;
	printf("Random point(1) OR Input point(0)\n");
	scanf("%d", &choice);
	if (choice == 1)
	{
		start = StartAndEnd(maze, (int)(row / 2), (int)(col / 2));
		end = StartAndEnd(maze, row, col);
	}
	else if (choice == 0)
	{
		int row = 0;
		int col = 0;
		printf("Please input startpoint row col\n");
		scanf("%d %d", &row, &col);
		start.arrrow = row * 2 - 1;
		start.arrcol = col * 2 - 1;

		printf("Please input endpoint row col\n");
		scanf("%d %d", &row, &col);
		end.arrrow = row * 2 - 1;
		end.arrcol = col * 2 - 1;
	}
	else
	{
		printf("Input ERROR\n");
		return -1;
	}

	//广度优先算法
	int flag = BFS(maze, start, end, mazerow, mazecol);

	//输出结果
	if (flag)
	{
		PrintMaze(maze, mazerow, mazecol);
		printf("step = %d\n", flag);
	}

	//释放内存
	for (int i = 0; i < mazerow; i++)
	{
		free(maze[i]);
	}
	free(maze);


	return 0;
}

四、实例运行结果

C语言课老师留的小作业,孩子记录一下。

迷宫我一开始是想做成完全没有死胡同的迷宫,任意两个点之间都有且仅有一条通路,即迷宫的通路构成一个树,但是没有想到怎么实现,就只好随机生成了,希望能有大佬提提意见。

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用广度优先搜索算法求解迷宫最短路径的 C 语言代码: ```c #include <stdio.h> #include <stdlib.h> #define ROW 10 // 迷宫行数 #define COL 10 // 迷宫列数 // 定义结构体表示坐标 typedef struct { int x; // 行坐标 int y; // 列坐标 } Coordinate; // 定义队列结构体 typedef struct { Coordinate data[ROW * COL]; // 队列数据 int front; // 队首指针 int rear; // 队尾指针 } Queue; // 初始化队列 void initQueue(Queue *q) { q->front = q->rear = 0; } // 判断队列是否为空 int isQueueEmpty(Queue *q) { return q->front == q->rear; } // 入队操作 void enqueue(Queue *q, Coordinate c) { q->data[q->rear++] = c; } // 出队操作 Coordinate dequeue(Queue *q) { return q->data[q->front++]; } // 判断坐标是否越界 int isOutOfBound(Coordinate c) { return c.x < 0 || c.y < 0 || c.x >= ROW || c.y >= COL; } // 判断坐标是否为墙 int isWall(int maze[ROW][COL], Coordinate c) { return maze[c.x][c.y] == 1; } // 判断坐标是否已经访问过 int isVisited(int visited[ROW][COL], Coordinate c) { return visited[c.x][c.y] == 1; } // 标记坐标已经访问过 void markVisited(int visited[ROW][COL], Coordinate c) { visited[c.x][c.y] = 1; } // 判断是否为出口 int isExit(Coordinate c, Coordinate exit) { return c.x == exit.x && c.y == exit.y; } // 广度优先搜索求解最短路径 int bfs(int maze[ROW][COL], Coordinate start, Coordinate exit) { int visited[ROW][COL] = {0}; // 标记已经访问过的坐标 int distance[ROW][COL] = {0}; // 记录起点到每个坐标的距离 Queue q; // 定义队列 initQueue(&q); // 初始化队列 enqueue(&q, start); // 入队起点 markVisited(visited, start); // 标记起点已经访问过 while (!isQueueEmpty(&q)) { Coordinate current = dequeue(&q); // 取出队首元素 if (isExit(current, exit)) { // 到达出口 return distance[current.x][current.y]; // 返回最短路径长度 } // 枚举当前坐标的四个方向 Coordinate dirs[4] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; for (int i = 0; i < 4; i++) { Coordinate next = {current.x + dirs[i].x, current.y + dirs[i].y}; if (isOutOfBound(next) || isWall(maze, next) || isVisited(visited, next)) { continue; // 如果下一个坐标越界、是墙或已经访问过,继续枚举下一个方向 } enqueue(&q, next); // 将下一个坐标入队 markVisited(visited, next); // 标记下一个坐标已经访问过 distance[next.x][next.y] = distance[current.x][current.y] + 1; // 更新下一个坐标的距离 } } return -1; // 没有找到最短路径 } int main() { int maze[ROW][COL] = { {0, 1, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 1, 0, 1, 1, 1, 0, 1, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 1, 1, 1, 1, 1, 1, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, {0, 1, 1, 1, 1, 1, 1, 1, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 1, 1, 1, 1, 1, 0} }; Coordinate start = {0, 0}; // 起点坐标 Coordinate exit = {9, 9}; // 出口坐标 int distance = bfs(maze, start, exit); // 求解最短路径长度 if (distance == -1) { printf("迷宫没有出口!\n"); } else { printf("最短路径长度为:%d\n", distance); } return 0; } ``` 以上代码中,我们使用了一个队列来存储待访问的坐标,使用二维数组 `visited` 记录已经访问过的坐标,使用二维数组 `distance` 记录起点到每个坐标的距离。在广度优先搜索算法中,我们每次取出队首元素,枚举其四个方向,对于每个方向,如果下一个坐标越界、是墙或已经访问过,则继续枚举下一个方向;否则,将下一个坐标入队,标记下一个坐标已经访问过,更新下一个坐标的距离。当取出的元素到达出口时,算法结束,返回最短路径长度。如果队列为空仍然没有找到出口,则说明迷宫没有出口。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值