您的位置:首页 > 其它

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

2013-04-27 16:54 429 查看
队列也是一组元素的集合,也提供两种基本操作: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: dameng34@163.com

> 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] =

{

    {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},

};

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 = { 0, 0, -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;

}

输出为:



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

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

int head = 0, tail = 0;

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



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

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



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



广度优先是一种步步为营的策略,每次都从各个方向探索一步,将前线推进一步,图中的虚线就表示这个前线,队列中的元素总是由前线的点组成的,可见正是队列先进先出的性质使这个算法具有了广度优先的特点。广度优先搜索还有一个特点是可以找到从起点到终点的最短路径,而深度优先搜索找到的不一定是最短路径。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: