如何用队列实现广度优先算法-C语言解决迷宫问题

广度优先搜索算法(也称宽度优先搜索,缩写BFS)是图里面常用的一种遍历算法。这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和广度优先搜索类似的思想。广度优先算法属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。基本过程,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。一般用数据结构队列来辅助实现BFS算法。

下面给出了一个例子,给大家详细的解析下广度优先是怎么搜索的。给出如图的图形结构(初始化全是白色),寻找v1到v7的最短路径:

在这里插入图片描述
1、访问起点v1(灰色),并且把起点v1的位置信息做进队操作。

在这里插入图片描述
2、已经访问了v1(黑色),下面可能的路径有三个,v2、v3、v4(灰色),把三个节点的位置信息同样的做进队操作。此时队列里面的路径已经有三个:v1->v2、v1->v3、v1->v4。

在这里插入图片描述3、对于v2而言,下面可能的路径有两个,v6和v3,但是v3已经访问过了,所以暂时忽略它。于是v6的位置信息进队。同样的,对v5和v7也做进队操作。此时队列里面有三条路径:v1->v2->v6、v1->v3->v5、v1->v4->v7。

在这里插入图片描述
4、此时已经访问了v7,于是搜索可以结束。队列里面存放了三条路径只有一条路径包含了v7,而且我们可以肯定的是,该路径也是最短的路径。

在这里插入图片描述看完这个例子,不知道大家有没有感触,总结一下,广度优先算法就是齐头并进,按照所有可能一起搜索下去。而且深度优先算法则跟它完全相反,认准一条路一直走下去,行不通再回来。

下面我们再次借用走迷宫的问题,只不过我们这次配合队列,使用广度优先搜索算法找到一条最佳路径。还是先看下问题:

问题描述:

以一个m*n的矩阵(二维数组)表示迷宫,0和1分别表示迷宫中的通路和障碍。迷宫问题要求求出从入口(0,0)到出口(m,n)的一条通路,或得出没有通路的结论。基本要求:首先实现一个以顺序表作存储结构的队列模型,然后编写一个求迷宫问题的非递归程序,求得最佳通路。其中:(x,y)指示迷宫中的一个坐标,pre表示该节点从哪个节点走过来。左上角(0,0)为入口,右下角(m,n)为出口。

#include <stdio.h>

#define SIZE      1024

struct Box     //表示一个格子的位置信息
{
    int x;     //横坐标
    int y;     //纵坐标
    int pre;   //前一个格子再在队列里面存放的位置(下标)
};
typedef struct Box Box;

//顺序队列存放路径的信息
struct Queue
{
    Box data[SIZE];
    int front;
    int rear;
};
typedef struct Queue Queue;

#include <stdio.h>

#define SIZE      1024

struct Box     //表示一个格子的位置信息
{
    int x;     //横坐标
    int y;     //纵坐标
    int pre;   //前一个格子再在队列里面存放的位置(下标)
};
typedef struct Box Box;

//顺序队列存放路径的信息
struct Queue
{
    Box data[SIZE];
    int front;
    int rear;
};
typedef struct Queue Queue;

int map[6][6] = { 
    {0, 0, 0, 1, 1, 1}, 
    {1, 1, 0, 0, 0, 0}, 
    {1, 1, 0, 1, 1, 0}, 
    {1, 1, 0, 0, 0, 0}, 
    {1, 1, 1, 0, 1, 1}, 
    {1, 1, 1, 0, 0, 1}, 
};

//初始化顺序队列
int InitQueue(Queue *q) 
{
    q->front = q->rear = -1;
    return 1;
}

//进队操作
int push(Queue *q, Box b)
{
    if (q->rear == SIZE - 1)
    {
        return 0;
    }
    (q->rear)++;
    q->data[q->rear] = b;

    return 1;
}

//判断队列是否为空
int EmptyQueue(Queue *q)
{
    return (q->front == q->rear) ? 1 : 0;
}

//出队操作(只是操作对头指针,元素实际还保留在队列中)
int pop(Queue *q, Box *b)
{
    if (q->front == q->rear)
    {
        return 0;
    }
    (q->front)++;
    *b = q->data[q->front];

    return 1;
}

//打印路径
void ShowPath(Queue *q, int front)
{
    int p = front, tmp;
    while (p != 0)
    {
        tmp = q->data[p].pre;
        q->data[p].pre = -1;
        p = tmp;
    }

    int i;
    for (i = 0; i <= q->rear; i++)
    {
        if (q->data[i].pre == -1)
        {
            printf("(%d, %d)->", q->data[i].x, q->data[i].y);
        }
    }
    printf("\n");
}

//入口(0,0) 出口(5,4)
int Walk(Queue *q, int x1, int y1, int x2, int y2)
{
    Box now;
    int i, j, i0, j0;

    now.x = x1;
    now.y = y1;
    now.pre = -1;

    push(q, now);            //入口信息入队
    map[x1][y1] = -1;

    while (EmptyQueue(q) != 1)
    {
        pop(q, &now);

        i = now.x;
        j = now.y;

        if (i == x2 && j == y2)       //出口
        {
            ShowPath(q, q->front);
            return 1;
        }

        int dir;
        for (dir = 0; dir < 4; dir++)   //循环四次,遍历四个方向  上  右  下  左
        {
            switch(dir)
            {
                case 0:            //方向上
                    i0 = i - 1;
                    j0 = j;
                    break;
                case 1:            //方向又
                    i0 = i;
                    j0 = j + 1;
                    break;
                case 2:           //方向下
                i0 = i + 1;
                    j0 = j;
                    break;
                case 3:           //方向左
                    i0 = i;
                    j0 = j - 1;
                    break;
            }
            //判断该点是否可走
            if (i0 >= 0 && j0 >= 0 && i0 <= 5 && j0 <= 5 && map[i0][j0] == 0)   //格子可以走
            {
                now.x = i0;
                now.y = j0;
                now.pre = q->front;

                push(q, now);
                map[i0][j0] = -1;     //该点已经走过
            }
        }
    }

    return 0;
}

int main()
{
    Queue queue;
    InitQueue(&queue);

    if (Walk(&queue, 0, 0, 5, 4) == 0)
    {
        printf("路径不存在\n");
    }

    return 0;
}

更多精彩视频、文章、嵌入式学习资料,微信关注 『学益得智能硬件』

在这里插入图片描述

  • 10
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是用C语言实现广度优先算法走迷宫的示例代码: ``` #include <stdio.h> #include <stdlib.h> #define MAX_ROW 5 #define MAX_COL 5 struct point { int row, col; } queue[512]; int maze[MAX_ROW][MAX_COL] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, }; int visited[MAX_ROW][MAX_COL]; int front = 0, rear = 0; void enqueue(struct point p) { queue[rear++] = p; } struct point dequeue(void) { return queue[front++]; } int is_empty(void) { return front == rear; } void visit(int row, int col, struct point pre) { struct point visit_point = { row, col }; maze[row][col] = 2; visited[row][col] = 1; printf("(%d, %d) ", row, col); if (pre.row != -1) printf("(%d, %d) ", pre.row, pre.col); enqueue(visit_point); } void bfs(int row, int col) { struct point p = { row, col }; enqueue(p); while (!is_empty()) { struct point current = dequeue(); if (maze[current.row][current.col] == 2) continue; if (current.row == MAX_ROW - 1 && current.col == MAX_COL - 1) { printf("(%d, %d)\n", current.row, current.col); printf("Congratulations, you have solved the maze!\n"); return; } visit(current.row, current.col - 1, current); visit(current.row - 1, current.col, current); visit(current.row, current.col + 1, current); visit(current.row + 1, current.col, current); } printf("Sorry, there is no path to the exit.\n"); } int main(void) { bfs(0, 0); return 0; } ``` 代码中,我们首先定义了一个5*5的迷宫,其中0表示可通行的路,1表示障碍物,2表示已经访问过的点。然后定义了一个point结构体作为队列中的元素,同时也定义了一个队列数组queue,用于存储待访问的点。visited数组用于记录哪些点已经被访问过。 enqueue函数用于将一个点加入队列中,dequeue函数用于从队列中取出一个点。is_empty函数用于判断队列是否为空。 visit函数用于访问一个点,将其标记为已访问,并将其加入队列中。bfs函数用于实现广度优先搜索,从起点开始遍历迷宫,遇到障碍物或已经访问过的点则跳过,否则访问该点,并将其相邻的四个点加入队列中。如果找到了终点,则输出路径并结束程序。如果队列为空仍未找到终点,则输出无法到达终点的提示信息。 在主函数中,我们调用bfs函数并传入起点坐标(0,0)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值