算法:队列与广度优先搜索(迷宫问题)

队列也是一组元素的集合,也提供两种基本操作:Enqueue(入队)将元素添加到队尾,Dequeue(出队)从队头取出元素并返回。就像排队买票一样,先来先服务,先入队的人也是先出队的,这种方式称为FIFO(First In First Out,先进先出),有时候队列本身也被称为FIFO。

下面我们用队列解决迷宫问题。程序如下:(参考《linux c 编程一站式学习》)

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/*************************************************************************
> File Name: breadth_search.c
> Author: Simba
> Mail: [email protected]
> Created Time: 2012年12月24日 星期一 19时24分37秒
************************************************************************/


#include<stdio.h>


#define MAX_ROW  5
#define MAX_COL  5

struct point
{
     int row, col, predecessor;
} queue[ 512];

int head =  0, tail =  0;

void enqueue( struct point p)
{
    queue[tail++] = p;
}

struct point dequeue( void)
{
     return queue[head++];
}

int is_empty( void)
{
     return head == tail;
}

int maze[MAX_ROW][MAX_COL] =
{
    { 01000},
    { 01010},
    { 00000},
    { 01110},
    { 00010},
};

void print_maze( void)
{
     int i, j;
     for (i =  0; i < MAX_ROW; i++)
    {
         for (j =  0; j < MAX_COL; j++)
            printf( "%d ", maze[i][j]);
        putchar( '\n');
    }
    printf( "*********\n");
}

void visit( int row,  int col)
{
     struct point visit_point = { row, col, head -  1 };
    maze[row][col] =  2;
    enqueue(visit_point);
}

int main( void)
{
     struct point p = {  00, - 1 };

    maze[p.row][p.col] =  2;
    enqueue(p);

     while (!is_empty())
    {
        p = dequeue();
         if (p.row == MAX_ROW -  1     /* goal */
                && p.col == MAX_COL -  1)
             break;
         if (p.col +  1 < MAX_COL  /* right */
                && maze[p.row][p.col +  1] ==  0)
            visit(p.row, p.col +  1);
         if (p.row +  1 < MAX_ROW  /* down */
                && maze[p.row +  1][p.col] ==  0)
            visit(p.row +  1, p.col);
         if (p.col -  1 >=  0   /* left */
                && maze[p.row][p.col -  1] ==  0)
            visit(p.row, p.col -  1);
         if (p.row -  1 >=  0   /* up */
                && maze[p.row -  1][p.col] ==  0)
            visit(p.row -  1, p.col);
        print_maze();
    }
     if (p.row == MAX_ROW -  1 && p.col == MAX_COL -  1)
    {
        printf( "(%d, %d)\n", p.row, p.col);
         while (p.predecessor != - 1)
        {
            p = queue[p.predecessor];
            printf( "(%d, %d)\n", p.row, p.col);
        }
    }
     else
        printf( "No path!\n");

     return  0;
}
输出为:

算法:队列与广度优先搜索(迷宫问题)_第1张图片

其实仍然可以像《用深度优先搜索解迷宫问题》一样用predecessor数组表示每个点的前趋,但我们可以换一种更方便的数据结构,直接在每个点的结构体中加一个成员表示前趋:
struct point { int row, col, predecessor; } queue[512];

int head = 0, tail = 0;
变量head和tail是队头和队尾指针,head总是指向队头,tail总是指向队尾的下一个元素。每个点的predecessor成员也是一个指针,指向它的前趋在queue数组中的位置。如下图所示:

算法:队列与广度优先搜索(迷宫问题)_第2张图片

这是一个静态分配的数组,每个数组元素都有row、col和predecessor三个成员,predecessor成员保存一个数组下标,指向数组中的另一个元素,这其实也是链表的一种形式,称为《静态链表》。

为了帮助理解,把这个算法改写成伪代码如下图:

算法:队列与广度优先搜索(迷宫问题)_第3张图片

从打印的搜索过程可以看出,这个算法的特点是沿各个方向同时展开搜索,每个可以走通的方向轮流往前走一步,这称为广度优先搜索(BFS,Breadth First Search)。探索迷宫和队列变化的过程如下图所示。

算法:队列与广度优先搜索(迷宫问题)_第4张图片

广度优先是一种步步为营的策略,每次都从各个方向探索一步,将前线推进一步,图中的虚线就表示这个前线,队列中的元素总是由前线的点组成的,可见正是队列先进先出的性质使这个算法具有了广度优先的特点。广度优先搜索还有一个特点是可以找到从起点到终点的最短路径,而深度优先搜索找到的不一定是最短路径。

你可能感兴趣的:(队列,广度优先搜索)