持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,[点击查看活动详情]
相关文章
基础知识
-
队列
- 定义:队列(Queue)是限定仅在表头进行删除操作、在表尾进行插入操作的线性表(先进先出)。进行插入操作的端称为队尾,进行删除操作的端称为队头。
- 存储形式:顺序存储(数组实现)、链式存储(链表实现)
-
BFS算法
- 宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一
- 与队列的关系:BFS算法是一种盲目搜索算法,需要按结点邻接关系遍历所有展开节点,而得到的子节点都会被加进一个先进先出的队列中。这就是队列在BFS算法中的应用。
题目
用队列求解迷宫问题的最短路径
思路
①实现链栈的常规操作:入队、出队、队列判空、获取队头元素等操作
②按照BFS的遍历顺序思想,依次访问邻接结点,将他们放入队列中
③遍历下去直到访问到目标结点为止
代码
//=====================测试3 BFS最短路径======================
class QueueNode //队列结点
{
public:
QueueNode() :x(-1), y(-1), next(NULL) {};
QueueNode(int m_x, int m_y, QueueNode* m_next = NULL) :x(m_x), y(m_y), next(m_next) {};
~QueueNode() { next = NULL; }
public:
int x, y; //储存当前结点距离起止位置的最短路线的距离
QueueNode* next; //储存下一个结点的指针
};
class LinkQueue //队列双向链表
{
public:
LinkQueue() { font = rear = new QueueNode(); }
void record(int m_x, int m_y);
void pop();
void print();
public:
int x, y; //记录结点代表的坐标
QueueNode* font;
QueueNode* rear;
};
void LinkQueue::record(int m_x, int m_y)
{
QueueNode* p = new QueueNode(m_x, m_y);
p->next = NULL;
rear->next = p; //注意
rear = p;
cout << '(' << m_x << ',' << m_y << ')' << "结点入队成功!" << endl;
}
void LinkQueue::pop()
{
if (font == rear) { //队空
cout << "链队为空,无法执行出队操作!" << endl;
return;
}
QueueNode* tmp = font->next;
font->next = tmp->next;
if (rear == tmp) //只剩下一个元素
{
rear = font;
}
cout << "(" << tmp->x << ',' << tmp->y << ')' << "出队成功!" << endl;
delete tmp;
}
void LinkQueue::print()
{
QueueNode* p = font;
while (p->next != NULL)
{
cout << '(' << p->next->x << ',' << p->next->y << ')' << "->";
p = p->next;
}
cout << "end" << endl;
}
struct Road
{
int x, y;
};
void test3() //BFS走迷宫-最短路径
{
cout << "=====================测试3 BFS之迷宫最短路径问题======================\n";
int m, n; //m行n列
//m = n = 5;
cout << "请输入要生成的迷宫的长和宽:";
cin >> m >> n;
//创建标记地图,记录是否走过
bool** sign_map = new bool*[m]; //存储迷宫是否走过
for (int i = 0; i < m; ++i)
{
sign_map[i] = new bool[n];
for (int t = 0; t < n; ++t)
{
sign_map[i][t] = true;
}
}
//创建地图
bool** map = new bool*[m]; //存储迷宫是否走过
for (int i = 0; i < m; ++i)
{
map[i] = new bool[n];
}
time_t tt;
srand((unsigned)time(&tt));
for (int i = 0; i < m; i++) //生成10个随机整数存入链表
{
if (i == 0 )
{
for (int j = 0; j < m + 2; ++j)
{
cout << "**";
}
cout << endl;
}
for (int t = 0; t < n; ++t)
{
if (i != 0 || i != m - 1)
{
if (t == 0) cout << "* ";
}
if ((i == 0 && t == 0) || (i == m - 1 && t == n - 1))
{
map[i][t] = true;
if (i == 0 && t == 0) cout << "起";
else cout << "终";
}
else
{
int is_wall = rand() % 10; //插入到位置i100-999随机整数
if (is_wall < 3) map[i][t] = false; //修改is_wall的值可以改变迷宫中墙壁出现的概率
else map[i][t] = true;
if (map[i][t] == true) cout << "□"; //⭕
else if (map[i][t] == false) cout << "×";
}
if (i != 0 || i != m - 1)
{
if (t == n-1) cout << " *";
}
}
cout << endl;
if (i == m-1)
{
for (int j = 0; j < m + 2; ++j)
{
cout << "**";
}
cout << endl;
}
}
//标记地图——复制地图用于初始化
for (int i = 0; i < m; ++i)
{
for (int t = 0; t < n; ++t)
{
sign_map[i][t] = map[i][t]; //true为未走,表示可以经过这个点,false表示已走或者墙壁
}
}
Road** road = new Road*[m]; //记录上个结点
for (int i = 0; i < m; ++i)
{
road[i] = new Road[n];
for (int t = 0; t < n; ++t)
{
road[i][t].x = -1;
road[i][t].y = -1;
}
}
LinkQueue* path = new LinkQueue();
path->record(0, 0); //记录起始位置
path->print();
sign_map[0][0] = false; //起始位置标记为走过
int xx = 0, yy = 0;
road[0][0].x = 0;
road[0][0].y = 0;
while (1)
{
if (path->font == path->rear) //头尾结点相等,表示到达终点
{
//输出路径,结束搜索
if (xx != m - 1 || yy != n - 1)
{
cout << "此迷宫找不到出路!" << endl;
break;
}
}
//搜索4个方向=====================================================
if (xx + 1 < m&&sign_map[xx + 1][yy] == true) //向下可走
{
path->record(xx + 1, yy);
sign_map[xx + 1][yy] = false; //走过的点标为false
road[xx + 1][yy].x = xx;
road[xx + 1][yy].y = yy;
}
if (yy + 1 < n&&sign_map[xx][yy + 1] == true) //向右可走
{
path->record(xx, yy + 1);
sign_map[xx][yy + 1] = false;
road[xx][yy + 1].x = xx;
road[xx][yy + 1].y = yy;
}
if (xx - 1 > 0 && sign_map[xx - 1][yy] == true) //向上可走
{
path->record(xx - 1, yy);
sign_map[xx - 1][yy] = false;
road[xx - 1][yy].x = xx;
road[xx - 1][yy].y = yy;
}
if (yy - 1 > 0 && sign_map[xx][yy - 1] == true) //向左可走
{
path->record(xx, yy - 1);
sign_map[xx][yy - 1] = false;
road[xx][yy - 1].x = xx;
road[xx][yy - 1].y = yy;
}
//搜索4个方向=====================================================finished!
path->pop();
if (path->font->next != NULL)
{
xx = path->font->next->x;
yy = path->font->next->y;
cout << "走到(" << xx << ',' << yy << ')' << endl;
}
path->print();
if (xx == m - 1 && yy == n - 1)
{
cout << "到达终点!" << endl;
Road r; //反向查找路径
int xx = m - 1;
int yy = n - 1;
Road* road_list = nullptr;
road_list = new Road[m*n];
road_list[0].x = m - 1;
road_list[0].y = n - 1;
int step = 1;
while (xx != 0 || yy != 0)
{
xx = road[xx][yy].x;
yy= road[xx][yy].y;
road_list[step].x = xx;
road_list[step].y = yy;
//cout << road_list[step].x << ',' << road_list[step].y << endl;
step++;
}
cout << "最短路径长为: " << step-1<<endl;
cout << "最短路径为:" << endl;
cout << "Start->";
for (int i = step - 1; i >= 0; --i)
{
cout << '(' << road_list[i].x << "," << road_list[i].y << ')' << "->";
}
cout << "End";
cout << endl;
break;
delete[]road_list;
}
}
//二维动态数组的删除
for (int i = 0; i < m; ++i)
{
delete[]sign_map[i];
}
delete[]sign_map;
for (int i = 0; i < m; ++i)
{
delete[]map[i];
}
delete[]map;
for (int i = 0; i < m; ++i)
{
delete[]road[i];
}
delete[]road;
}
int main()
{
test1();
cout << '\n';
test2();
cout << '\n';
test3();
cout << '\n';
}
结果