1. 背景说明
广度优先通俗的解释的是将当前所有能走的步骤全部走完并保存在队列中,又称为层序遍历,此外,该方法类似于多条路线并发前进,
哪一条先到就取哪条路线作为结果并终止查询,因此能够得到最短路径,缺点是由于遍历的点太多,效率低下。
输入文本
10 10
18
1 3
1 7
2 3
2 7
3 5
3 6
4 2
4 3
4 4
5 4
6 2
6 6
7 2
7 3
7 4
7 6
7 7
8 1
1 1
8 8
2. 示例代码
1)status.h
/* DataStructure 预定义常量和类型头文件 */
#ifndef STATUS_H
#define STATUS_H
/* 函数结果状态码 */
#define TRUE 1 /* 返回值为真 */
#define FALSE 0 /* 返回值为假 */
#define RET_OK 0 /* 返回值正确 */
#define INFEASIABLE 2 /* 返回值未知 */
#define ERR_MEMORY 3 /* 访问内存错 */
#define ERR_NULL_PTR 4 /* 空指针错误 */
#define ERR_MEMORY_ALLOCATE 5 /* 内存分配错 */
#define ERR_NULL_STACK 6 /* 栈元素为空 */
#define ERR_PARA 7 /* 函数参数错 */
#define ERR_OPEN_FILE 8 /* 打开文件错 */
#define ERR_NULL_QUEUE 9 /* 队列为空错 */
#define ERR_FULL_QUEUE 10 /* 队列为满错 */
typedef int Status; /* Status 是函数的类型,其值是函数结果状态代码,如 RET_OK 等 */
typedef int Bollean; /* Boolean 是布尔类型,其值是 TRUE 或 FALSE */
#endif // !STATUS_H
2) sqQueue.h
/* 顺序队列实现头文件 */
#ifndef SQQUEUE_H
#define SQQUEUE_H
#include "status.h"
#define MAX_QUEUE_SIZE 5
typedef struct {
int x;
int y;
int preOrder;
} QElemType;
typedef struct {
QElemType *base;
int front;
int rear;
} SqQueue;
/* 构造一个空队列 Q */
Status InitQueue(SqQueue *Q);
/* 销毁队列 Q */
Status DestroyQueue(SqQueue *Q);
/* 将 Q 清为空队列 */
void ClearQueue(SqQueue *Q);
/* 若队列 Q 为空队列,则返回 TRUE,否则返回 FALSE */
Bollean QueueEmpty(const SqQueue *Q);
/* 返回 Q 的元素个数,即队列的长度 */
int QueueLength(const SqQueue *Q);
/* 若队列不空,则用 e 返回 Q 的队头元素,并返回 OK */
Status GetQueueHead(const SqQueue *Q, QElemType *e);
/* 插入元素 e 为 Q 的新的队尾元素 */
Status EnQueue(QElemType e, SqQueue *Q);
/* 若队列不空,则删除 Q 的队头元素,用 e 返回其值,并返回 OK */
Status DeQueue(SqQueue *Q, QElemType *e);
/* 从队头到队尾依次对队列 Q 中每个元素调用函数 vi() */
Status QueueTraverse(const SqQueue *Q, void(*vi)(QElemType));
#endif // !SQQUEUE_H
3) sqQueue.c
/* 顺序队列实现源文件 */
#include "sqQueue.h"
#include <stdio.h>
#include <stdlib.h>
static Bollean QueueFull(const SqQueue *Q)
{
return (Q->rear >= MAX_QUEUE_SIZE) ? TRUE : FALSE;
}
/* 构造一个空队列 Q */
Status InitQueue(SqQueue *Q)
{
Q->base = (QElemType *)malloc(sizeof(QElemType) * MAX_QUEUE_SIZE);
if (!Q->base) {
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
return ERR_MEMORY_ALLOCATE;
}
Q->front = Q->rear = 0;
return RET_OK;
}
/* 销毁队列 Q */
Status DestroyQueue(SqQueue *Q)
{
if (Q->base) {
free(Q->base);
}
Q->base = NULL;
Q->front = Q->rear = 0;
return RET_OK;
}
/* 将 Q 清为空队列 */
void ClearQueue(SqQueue *Q)
{
Q->front = Q->rear = 0;
}
/* 若队列 Q 为空队列,则返回 TRUE,否则返回 FALSE */
Bollean QueueEmpty(const SqQueue *Q)
{
return (Q->front == Q->rear) ? TRUE : FALSE;
}
/* 返回 Q 的元素个数,即队列的长度 */
int QueueLength(const SqQueue *Q)
{
return (Q->rear - Q->front);
}
/* 若队列不空,则用 e 返回 Q 的队头元素,并返回 OK */
Status GetQueueHead(const SqQueue *Q, QElemType *e)
{
if (Q->front == Q->rear) {
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_QUEUE);
return ERR_NULL_QUEUE;
}
*e = *(Q->base + Q->front);
return RET_OK;
}
/* 插入元素 e 为 Q 的新的队尾元素 */
Status EnQueue(QElemType e, SqQueue *Q)
{
if (QueueFull(Q)) {
Q->base = (QElemType *)realloc(Q->base, sizeof(QElemType) * (unsigned long long)(Q->rear + 1));
if (!Q->base) {
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
return ERR_MEMORY_ALLOCATE;
}
}
Q->base[Q->rear] = e;
Q->rear = ++(Q->rear);
return RET_OK;
}
/* 若队列不空,则删除 Q 的队头元素,用 e 返回其值,并返回 OK */
Status DeQueue(SqQueue *Q, QElemType *e)
{
if (QueueEmpty(Q)) {
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_QUEUE);
return ERR_NULL_QUEUE;
}
*e = Q->base[Q->front];
Q->front = Q->front + 1;
return RET_OK;
}
/* 从队头到队尾依次对队列 Q 中每个元素调用函数 vi() */
Status QueueTraverse(const SqQueue *Q, void(*vi)(QElemType))
{
int pos = Q->front;
while (pos != Q->rear) {
vi(Q->base[pos]);
++pos;
}
return RET_OK;
}
4) sqStack.h
/* 栈的顺序存储表示头文件 */
#ifndef SQSTACK_H
#define SQSTACK_H
#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */
#define STACKINCREMENT 2 /* 存储空间分配增量 */
#include "status.h"
typedef struct {
int x;
int y;
int preOrder;
} SElemType;
typedef struct SqStack {
SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */
SElemType *top; /* 栈顶指针 */
int stackSize; /* 当前已分配的存储空间,以元素为单位 */
} SqStack; /* 顺序栈 */
/* 构造一个空栈 S */
Status InitStack(SqStack *S);
/* 销毁栈 S */
void DestroyStack(SqStack *S);
/* 把 S 置为空栈 */
void ClearStack(SqStack *S);
/* 若栈 S 为空栈,则返回 TRUE,否则返回 FALSE */
Status StackEmpty(SqStack S);
/* 返回 S 的元素个数,即栈的长度 */
int StackLength(SqStack S);
/* 若栈不空,则用 e 返回 S 的栈顶元素,并返回 OK;否则返回 ERROR */
Status GetTop(SqStack S, SElemType *e);
/* 插入元素 e 为新的栈顶元素 */
Status Push(SqStack *S, SElemType e);
/* 若栈不空,则删除 S 的栈顶元素,用 e 返回其值,并返回 OK;否则返回 ERROR */
Status Pop(SqStack *S, SElemType *e);
/* 从栈底到栈顶依次对栈中每个元素调用函数 visit() */
void StackTraverse(SqStack S, void(*Visit)(SElemType));
#endif
5) sqStack.c
/* 栈的顺序存储表示源文件 */
#include "sqStack.h"
#include "status.h"
#include <stdlib.h>
#include <stdio.h>
/* 构造一个空栈 S */
Status InitStack(SqStack *S)
{
(*S).base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if (!(*S).base) {
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
return ERR_MEMORY_ALLOCATE;
}
(*S).top = (*S).base;
(*S).stackSize = STACK_INIT_SIZE;
return RET_OK;
}
/* 销毁栈 S */
void DestroyStack(SqStack *S)
{
free((*S).base);
(*S).base = NULL;
(*S).top = NULL;
(*S).stackSize = 0;
}
/* 把 S 置为空栈 */
void ClearStack(SqStack *S)
{
(*S).top = (*S).base;
}
/* 若栈 S 为空栈,则返回 TRUE,否则返回 FALSE */
Status StackEmpty(SqStack S)
{
return (S.top == S.base) ? TRUE : FALSE;
}
/* 返回 S 的元素个数,即栈的长度 */
int StackLength(SqStack S)
{
return (int)(S.top - S.base);
}
/* 若栈不空,则用 e 返回 S 的栈顶元素,并返回 OK;否则返回 ERROR */
Status GetTop(SqStack S, SElemType *e)
{
if (S.top > S.base) {
*e = *(S.top - 1);
return RET_OK;
}
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_STACK);
return ERR_NULL_STACK;
}
/* 插入元素 e 为新的栈顶元素 */
Status Push(SqStack *S, SElemType e)
{
if (((*S).top - (*S).base) == (*S).stackSize) {
(*S).base = (SElemType *)realloc((*S).base, (unsigned long long)(((*S).stackSize) + STACKINCREMENT) * sizeof(SElemType));
if (!(*S).base) {
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
return ERR_MEMORY_ALLOCATE;
}
(*S).top = (*S).base + (*S).stackSize;
(*S).stackSize += STACKINCREMENT;
}
*((*S).top)++ = e;
return RET_OK;
}
/* 若栈不空,则删除 S 的栈顶元素,用 e 返回其值,并返回 OK;否则返回 ERROR */
Status Pop(SqStack *S, SElemType *e)
{
if ((*S).top == (*S).base) {
printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
return ERR_MEMORY_ALLOCATE;
}
*e = *(--(*S).top);
return RET_OK;
}
/* 从栈底到栈顶依次对栈中每个元素调用函数 visit() */
void StackTraverse(SqStack S, void(*Visit)(SElemType))
{
while (S.top > S.base) {
Visit(*S.base++);
}
}
6) algorithm.h
/* 算法定义头文件 */
#ifndef ALGORITHM_H
#define ALGORITHM_H
#include "status.h"
/* 迷宫位置坐标 */
typedef struct {
int x;
int y;
} MazePosition;
#define D 8
#define MAXLENGTH 25 /* 设迷宫最大行列为 25 */
/* 定义墙元素值为 0,可通过路径为 -2, 不能通过路径为 -1 */
typedef int MazeType[MAXLENGTH][MAXLENGTH];
/* 利用非循环顺序队列采用广度搜索法求解迷宫问题, 求得第一条 路径,并返回 TRUE;否则返回 FALSE */
Status MazePath(const MazePosition start, const MazePosition end, MazeType *maze, int *totalStep);
/* 如果存在路径,输出求得的迷宫的解 */
void PrintMazePath(int row, int col, MazeType *maze);
#endif // !ALGORITHM_H
7) algorithm.c
/* 算法实现源文件 */
#include <windows.h>
#include "algorithm.h"
#include "sqStack.h"
#include "sqQueue.h"
#include <stdio.h>
/* 勿在头文件中定义,否则会重复包含 */
#if D == 4
MazePosition direc[D] = { { -1, 0 }, { 1 , 0 }, { 0, -1 }, { 0, 1 } };
#endif
#if D == 8
MazePosition direc[D] = { { -1, 0 }, { 1 , 0 }, { 0, -1 }, { 0, 1 },
{ -1, -1 }, { -1, 1 }, { 1, -1 }, { 1, 1 } };
#endif
/* 定义墙元素值为 0,可通过路径为 -2, 不能通过路径为 -1, 通过路径为足迹
当迷宫 maze 的 curPos 点的序号为 -2(可通过路径),return OK; 否则,return FALSE */
static Bollean PassPos(QElemType curPos, MazeType *maze)
{
return ((*maze)[curPos.x][curPos.y] == -2) ? TRUE : FALSE;
}
/* 判断两个位置是否相同,相同返回 TRUE, 否则返回 FALSE */
static Bollean PostionSame(MazePosition pos1, QElemType pos2)
{
return ((pos1.x == pos2.x) && (pos1.y == pos2.y)) ? TRUE : FALSE;
}
/* 利用非循环顺序队列采用广度搜索法求解迷宫问题, 求得第一条 路径,并返回 TRUE;否则返回 FALSE */
Status MazePath(MazePosition start, MazePosition end, MazeType *maze, int *totalStep)
{
SqQueue Q;
InitQueue(&Q);
QElemType qECurr = { 0 };
qECurr.preOrder = -1;
qECurr.x = start.x;
qECurr.y = start.y;
(*maze)[qECurr.x][qECurr.y] = -1;
EnQueue(qECurr, &Q);
Bollean flag = FALSE;
QElemType qENext = { 0 };
while ((!QueueEmpty(&Q)) && (!flag)) {
DeQueue(&Q, &qECurr);
for (int i = 0; i < D; ++i) {
qENext.x = qECurr.x + direc[i].x;
qENext.y = qECurr.y + direc[i].y;
if (PassPos(qENext, maze)) {
(*maze)[qENext.x][qENext.y] = -1;
qENext.preOrder = Q.front - 1;
EnQueue(qENext, &Q);
if (PostionSame(end, qENext)) {
flag = TRUE;
break;
}
}
}
}
if (flag) {
SqStack S;
InitStack(&S);
int pos = Q.rear - 1;
while (pos >= 0) {
SElemType sE = { Q.base[pos].x, Q.base[pos].y, Q.base[pos].preOrder };
Push(&S, sE);
pos = (Q.base[pos]).preOrder;
}
*totalStep = 0;
SElemType sE;
while (!StackEmpty(S)) {
Pop(&S, &sE);
++(*totalStep);
(*maze)[sE.x][sE.y] = *totalStep;
}
return TRUE;
}
printf("No way!\n");
return FALSE;
}
/* 设置字体颜色,入参为 0 - 15 */
static void SetColor(const unsigned short textColor)
{
if ((textColor >= 0) && (textColor <= 15)) {
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), textColor);
} else {
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}
}
/* 如果存在路径,输出求得的迷宫的解 */
void PrintMazePath(int row, int col, MazeType *maze)
{
for (int i = 0; i < row; ++i) {
for (int j = 0; j < col; ++j) {
if ((*maze)[i][j] > 0) {
SetColor(2);
printf("%3d", (*maze)[i][j]);
} else {
SetColor(7);
printf("%3d", (*maze)[i][j]);
}
}
printf("\n");
}
}
8) main.c
/* 入口程序源文件 */
#include "algorithm.h"
#include <stdio.h>
int main(void)
{
printf("Please input the row and col of the maze: ");
int row = 0, col = 0;
scanf_s("%d%d", &row, &col);
MazeType maze = { 0 };
for (int i = 0; i < col; ++i) {
maze[0][i] = 0;
maze[row - 1][i] = 0;
}
for (int i = 1; i < row - 1; ++i) {
maze[i][0] = 0;
maze[i][row - 1] = 0;
}
for (int i = 1; i < row - 1; ++i) {
for (int j = 1; j < col - 1; ++j) {
maze[i][j] = -2;
}
}
printf("Please input the num of the wall: ");
int wallNum = 0;
scanf_s("%d", &wallNum);
printf("Please input the position of the wall(x, y): \n");
int x = 0, y = 0;
for (int i = 0; i < wallNum; ++i) {
scanf_s("%d%d", &x, &y);
maze[x][y] = 0;
}
printf("The structure of the maze is:\n");
PrintMazePath(row, col, &maze);
MazePosition start = { 0 }, end = { 0 };
printf("Please input the position of the start point(x, y):");
scanf_s("%d%d", &start.x, &start.y);
printf("Please input the position of the end point(x, y):");
scanf_s("%d%d", &end.x, &end.y);
int totalStep;
if (MazePath(start, end, &maze, &totalStep)) {
printf("\nUse %d steps, one of the path from start to end of the maze is:\n\n", totalStep);
PrintMazePath(row, col, &maze);
} else {
printf("There is no way to the end.\n");
}
return 0;
}
3. 输出示例