如何用隊列實現廣度優先算法-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;
}

更多精彩視頻、文章、嵌入式學習資料,微信關注 『學益得智能硬件』

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章