问题描述:给定一副地图,一个开始坐标,一个结束坐标,寻找一条可以从开始坐标到结束坐标的最短路径
定义数据类型如下:
typedef struct node { int step=0;//从起点到该点的步数 int x; int y; } path, node;
问题分析:通过广度优先的思想,借助队列的结构,一层一层标记地图上从起点到各个点的距离,算出最短距离,判断每个点的距离是否连续,找到终点即为最短的路径。先压入队列起点,弹出队列头部元素,通过方向数组判断方向,在将其相邻的元素压入队列,标记步数,以此循环
核心代码:
int v[100][100];//判断是否走过 //方向数组 int dx[4] = { 0,1,0,-1 }; int dy[4] = { 1,0,-1,0 }; void bfs_maze(node start, node end) { LinkQueue q = InitQueue();//初始化队列 start.step = 1;//将起点标记为1 q=Enqueue(q, start);//压入队列 v[start.x][start.y] = 1;//标记该点为以走过 int flag = 0;//判断是否可通的标记 while (!Empty(q)) { node front_item;//临时变量暂存队首元素 q=DelQueue(q, &front_item);//删除队首元素 if (front_item.x==end.x&&front_item.y==end.y)//找到的终点 { flag = 1; break; } for (int i = 0; i < 4; i++) { int tempx = front_item.x + dx[i];//通过方向数组的下一个横坐标 int tempy = front_item.y + dy[i];//通过方向数组的下一个纵坐标 if (tempx >= 0 && tempx < len && tempy >= 0 && tempy < len) {//是否越界 if (maze[tempx][tempy]==1&&v[tempx][tempy]==0)//该点从未走过且为地图上可通的点 { node temp; temp.x = tempx; temp.y = tempy; temp.step = front_item.step + 1; maze[tempx][tempy] = temp.step;//标记步数 q=Enqueue(q, temp);//压入队列中 v[tempx][tempy] = 1;//该点已走过 } } } } if (flag==0) { printf("不可通!"); } }
完整代码如下:
#include<stdio.h> #include<malloc.h> typedef struct node { int step=0; int x; int y; } path, node; typedef struct Qnode { node data;//其中数据域data为抽象元素类型 struct Qnode* next;//其中next为指针类型 }Qnode, * QueuePtr;//其中,Qnode为结点类型, QueuePtr:指向Qnode的指针类型 typedef struct { Qnode* front;//头指针 Qnode* rear;//尾指针 }LinkQueue;//链式队列类型 //生成空队列算法:初始化队列 #define LENG sizeof(Qnode)//求结点所占的单元数 LinkQueue InitQueue()//生成仅带表头结点的空队列Q { LinkQueue Q;//说明变量Q Q.front = Q.rear = (QueuePtr)malloc(LENG);//生成表头结点 Q.front->next = NULL;//表头结点的next为空指针 return Q;//返回Q的值 } //(非)空队列时插入新元素x LinkQueue Enqueue(LinkQueue Q, node e) { Qnode* p;//说明变量p p = (Qnode*)malloc(LENG);//生成新元素结点 p->data = e;//装入元素e p->next = NULL;//为队尾结点 Q.rear->next = p;//插入新结点 Q.rear = p;//修改尾指针 return Q;//返回Q的新值 } //链式队列的出队算法 LinkQueue DelQueue(LinkQueue Q, node* e) { Qnode* p;//声明变量p if (Q.front == Q.rear)//若原队列为空 { printf("Empty queue");//空队列 return Q; } p = Q.front->next;//p指向要删除的队头结点 (*e) = p->data;//取出元素 Q.front->next = p->next;//删除队头结点 if (Q.rear == p)//若原队列只有1个结点 { Q.rear = Q.front;//修改尾指针 } free(p);//释放被删除的空间 return Q;//返回出队后的Q } bool Empty(LinkQueue& q) { if (q.rear==q.front) { return true; } return false; } int dx2[4] = { 1,0,0,-1 }; int dy2[4] = { 0,1,-1,0 }; int maze[6][6] = { {0,1,0,0,0,0}, {0,1,1,1,1,0}, {0,1,0,1,0,0}, {0,1,0,1,1,0}, {0,1,1,0,1,0}, {0,0,1,1,1,0} }; int len = 6; int v[100][100];//判断是否走过 //方向数组 int dx[4] = { 0,1,0,-1 }; int dy[4] = { 1,0,-1,0 }; void bfs_maze(node start, node end) { LinkQueue q = InitQueue(); start.step = 1; q=Enqueue(q, start); v[start.x][start.y] = 1; int flag = 0; while (!Empty(q)) { node front_item; q=DelQueue(q, &front_item); if (front_item.x==end.x&&front_item.y==end.y) { flag = 1; break; } for (int i = 0; i < 4; i++) { int tempx = front_item.x + dx[i]; int tempy = front_item.y + dy[i]; if (tempx >= 0 && tempx < len && tempy >= 0 && tempy < len) { if (maze[tempx][tempy]==1&&v[tempx][tempy]==0) { node temp; temp.x = tempx; temp.y = tempy; temp.step = front_item.step + 1; maze[tempx][tempy] = temp.step; q=Enqueue(q, temp); v[tempx][tempy] = 1; } } } } if (flag==0) { printf("不可通!"); } } void printMaze() { for (int i = 0; i < 6; i++) { for (int j = 0; j < 6; j++) { printf("%d ", maze[i][j]); } printf("\n"); } printf("\n"); } void printMaze2(node start, node end) { while (start.step != end.step) { start.step++; for (int i = 0; i < 4; i++) { int tmpx = start.x + dx2[i]; int tmpy = start.y + dy2[i]; if (tmpx >= 0 && tmpx < len && tmpy >= 0 && tmpy < len) { if (maze[tmpx][tmpy] == start.step) { printf("%d %d\n", tmpx, tmpy); start.x = tmpx; start.y = tmpy; break; } } } } } int main() { node start, end; start.x = 0; start.y = 1; end.x = 5; end.y = 2; printMaze(); bfs_maze(start, end); printMaze(); start.step = maze[start.x][start.y]; end.step = maze[end.x][end.y]; printMaze2(start,end); //printRoad(start); }