赞
踩
目录
BFS(广度优先探索),与 DFS(深度优先探索) 相对应。形象地说,是一种从起点开始不断向外扩散搜索的一种搜索算法。
如图,黑色色块代表起点,灰色代表未搜索色块,灰白色代表已搜索色块,蓝色代表当前本轮搜索到的色块,绿色代表下一轮将搜索的色块,红色代表终点。
(形象化描述)该算法中,首先需要一个 标记遍历的数组 ,记录已搜索过的地方。其次,对于本轮与下一轮的顺序处理,需要使用 队列 进行依次处理,这样保证了只有待上一轮处理完才会轮到下一轮处理。
对于本轮搜索的每一个元素,会将其从队首弹出并判断是否为终点,然后将符合搜索条件的下一轮元素从队尾入队,如果无符合搜索条件的下一轮元素,则无新的元素入队。若到搜索完毕都没发现终点,则不再有新的元素入队,最后一轮元素不断退队直至队列为空;若搜索到终点,则不再搜索, 队伍剩余元素不断退队直至队列为空。
总而言之,BFS是 顺序处理 上一轮与这一轮的元素,直至搜索到终点或再无符合搜索条件元素入队。
如今有一搜索范围,确定起点与终点。
初始化:初始化标记遍历都为 0;生成队列,将起点入队,标记为 1。
搜索条件:标记遍历不为 1,地图不为墙。
循环操作:(循环终止条件:队列为空)
(1) 将队首(此时为起点)弹出,并判断是否为终点(否,继续搜索)。
(2) 向四周查找符合搜索条件的元素,将这些元素逐个入队,标记为1。同时判断是否为终点(否,继续搜索)。
进入 下一个循环 :
(1) 将队首(此时为起点上方的元素)弹出,并判断是否为终点(否,继续搜索)。
(2) 向四周查找符合搜索条件的元素,将这些元素逐个入队,标记为1。判断是否为终点(否,继续搜索)。
......处理至下一轮并 继续循环 :
边界处:只将符合搜索条件的元素入队即可。
搜索到终点:停止继续搜索,不再有新元素入队,队列中剩余元素直接逐个出队直至空。
结束后:
固定头节点 head
- typedef struct node
- {
- // 坐标记录
- int x;
- int y;
- // 第n轮搜索
- int step;
- // 链表链接
- struct node *next;
- } node;
-
- // 头节点
- node *head;
入队
- void push(node *newNode)
- {
- node *p = head;
- // 遍历至队尾
- while (p->next != NULL)
- {
- p = p->next;
- }
- // 链接
- p->next = newNode;
- }
出队
- void pop()
- {
- // 删除头节点下一节点
- node *temp = head->next;
- head->next = temp->next;
- free(temp);
- }
Map & Sign
- #define ROW 8
- #define COL 8
- // ROW * COL Map
- // 0为路径,1为墙,2为终点
- int map[ROW + 2][COL + 2] = {
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
- {1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
- {1, 1, 1, 1, 0, 1, 1, 1, 1, 1},
- {1, 0, 0, 1, 0, 0, 1, 0, 1, 1},
- {1, 0, 1, 0, 0, 1, 1, 0, 1, 1},
- {1, 0, 1, 0, 1, 1, 1, 0, 1, 1},
- {1, 0, 1, 0, 0, 0, 0, 0, 1, 1},
- {1, 0, 0, 0, 1, 1, 1, 0, 1, 1},
- {1, 1, 1, 1, 1, 1, 1, 0, 2, 1},
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
- };
- int sign[ROW + 2][COL + 2] = {};
方向
- // += direction[i].x
- // += direction[i].y
- struct
- {
- int x;
- int y;
- } direction[4] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
- // 以 x, y 坐标为起点
- int bfs(int x, int y)
- {
- // 记录最小步数
- int MinStep = 0;
- // 记录是否已抵达终点
- int flag = 0;
-
- // 初始化头节点
- head = (node *)malloc(sizeof(node));
- head->next = NULL;
-
- // 起点节点入队
- node *start = (node *)malloc(sizeof(node));
- start->x = x;
- start->y = y;
- start->step = 0;
- start->next = NULL;
-
- push(start);
-
- // 标记遍历为 1
- sign[x][y] = 1;
- // 在地图上标记起点为 5
- map[x][y] = 5;
-
- do
- {
- // 提取队首(注意此时还未出队)
- node *prevNode = head->next;
-
- // 如果当前已找到终点,队首直接出队,不再继续搜索
- if (flag)
- {
- pop();
- continue;
- }
-
- // 未找到,继续搜索
- int i;
- for (i = 0; i < 4; ++i)
- {
- // 对四个方向进行搜索判断
- // 新建节点存储待判断元素信息
- node *newNode = (node *)malloc(sizeof(node));
- newNode->x = prevNode->x + direction[i].x;
- newNode->y = prevNode->y + direction[i].y;
- newNode->step = prevNode->step + 1;
- newNode->next = NULL;
-
- // 若找到终点,标记后不再搜索
- if (map[newNode->x][newNode->y] == 2)
- {
- flag = 1;
- // 地图上标记为 3
- map[newNode->x][newNode->y] = 3;
- // 记录最小步数
- MinStep = newNode->step;
- free(newNode);
- break;
- }
-
- // 若符合搜索条件,入队并标记
- else if (sign[newNode->x][newNode->y] == 0 && map[newNode->x][newNode->y] == 0)
- {
- // 入队
- push(newNode);
- // 标记遍历为 1
- sign[newNode->x][newNode->y] = 1;
- // 地图上标记为 3
- map[newNode->x][newNode->y] = 3;
- }
- // 不符合搜索条件
- else
- free(newNode);
- }
- // 此处的下一级元素全部入队后,队首出队
- pop();
- } while (head->next != NULL);
-
- return MinStep;
- }
- int main()
- {
- // 输出初始Map状态
- int i, j;
- for (i = 1; i <= ROW; ++i)
- {
- for (j = 1; j <= COL; ++j)
- {
- printf("%d ", map[i][j]);
- }
- putchar(10);
- }
- putchar(10);
-
- // BFS 从 1,1 开始
- int MinStep = bfs(1, 1);
-
- // 输出最小步数
- if (MinStep)
- printf("MinStep = %d\n", MinStep);
- else
- printf("Not Found!");
-
- for (i = 1; i <= ROW; ++i)
- {
- for (j = 1; j <= COL; ++j)
- {
- printf("%d ", map[i][j]);
- }
- putchar(10);
- }
-
- // 小心内存泄漏
- free(head);
- return 0;
- }
- #include <stdio.h>
- #include <stdlib.h>
-
- #define ROW 8
- #define COL 8
-
- typedef struct node
- {
- int x;
- int y;
- int step;
- struct node *next;
- } node;
- node *head;
-
- struct
- {
- int x;
- int y;
- } direction[4] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
-
- int map[ROW + 2][COL + 2] = {
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
- {1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
- {1, 1, 1, 1, 0, 1, 1, 1, 1, 1},
- {1, 0, 0, 1, 0, 0, 1, 0, 1, 1},
- {1, 0, 1, 0, 0, 1, 1, 0, 1, 1},
- {1, 0, 1, 0, 1, 1, 1, 0, 1, 1},
- {1, 0, 1, 0, 0, 0, 0, 0, 1, 1},
- {1, 0, 0, 0, 1, 1, 1, 0, 1, 1},
- {1, 1, 1, 1, 1, 1, 1, 0, 2, 1},
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
- };
- int sign[ROW + 2][COL + 2] = {};
-
- void push(node *newNode)
- {
- node *p = head;
- while (p->next != NULL)
- {
- p = p->next;
- }
- p->next = newNode;
- }
-
- void pop()
- {
- node *temp = head->next;
- head->next = temp->next;
- free(temp);
- }
-
- int bfs(int x, int y)
- {
- int MinStep = 0;
- int flag = 0;
-
- head = (node *)malloc(sizeof(node));
- head->next = NULL;
-
- node *start = (node *)malloc(sizeof(node));
- start->x = x;
- start->y = y;
- start->step = 0;
- start->next = NULL;
-
- push(start);
-
- sign[x][y] = 1;
- map[x][y] = 5;
-
- do
- {
- node *prevNode = head->next;
-
- if (flag)
- {
- pop();
- continue;
- }
-
- int i;
- for (i = 0; i < 4; ++i)
- {
- node *newNode = (node *)malloc(sizeof(node));
- newNode->x = prevNode->x + direction[i].x;
- newNode->y = prevNode->y + direction[i].y;
- newNode->step = prevNode->step + 1;
- newNode->next = NULL;
-
- if (map[newNode->x][newNode->y] == 2)
- {
- flag = 1;
- map[newNode->x][newNode->y] = 3;
- MinStep = newNode->step;
- free(newNode);
- break;
- }
-
- else if (sign[newNode->x][newNode->y] == 0 && map[newNode->x][newNode->y] == 0)
- {
- push(newNode);
- sign[newNode->x][newNode->y] = 1;
- map[newNode->x][newNode->y] = 3;
- }
- else
- free(newNode);
- }
- pop();
- } while (head->next != NULL);
- return MinStep;
- }
-
- int main()
- {
- int i, j;
- for (i = 1; i <= ROW; ++i)
- {
- for (j = 1; j <= COL; ++j)
- {
- printf("%d ", map[i][j]);
- }
- putchar(10);
- }
- putchar(10);
-
- int MinStep = bfs(1, 1);
-
- if(MinStep)
- printf("Min step = %d\n", MinStep);
- else
- printf("Not Found!");
-
- for (i = 1; i <= ROW; ++i)
- {
- for (j = 1; j <= COL; ++j)
- {
- printf("%d ", map[i][j]);
- }
- putchar(10);
- }
-
- free(head);
- return 0;
- }
首先,要求记录每一子节点的父节点。
于是,应在结构体中增加父节点指针。
- typedef struct node
- {
- struct node *prev; // 父节点
- int x;
- int y;
- int step;
- struct node *next;
- } node;
其次,所有入队节点应保留用于回溯查询。
于是,不能弹出队首,应将指针指向下一节点。
最后,要记得 free 防止内存泄漏哦!
- void quit()
- {
- while (head->next != NULL)
- {
- node *temp = head->next;
- head->next = temp->next;
- free(temp);
- }
- free(head);
- head = NULL;
- }
从终点开始不断向前找父节点直至 NULL 。
- void route()
- {
- node *p = head;
- // 遍历到队尾(终点节点)
- while (p->next != NULL)
- {
- p = p->next;
- }
- // 从终点节点的上一节点开始向前寻找路径(父节点)
- p = p->prev;
- while (p->prev != NULL)
- {
- // 在地图上标记为 4
- map[p->x][p->y] = 4;
- // 向前到父节点
- p = p->prev;
- }
- }
- #include <stdio.h>
- #include <stdlib.h>
-
- #define ROW 8
- #define COL 8
- // 高亮显示
- #define Green "\033[1;32m"
- // 清除高亮
- #define None "\033[m"
-
- typedef struct node
- {
- struct node *prev;
- int x;
- int y;
- int step;
- struct node *next;
- } node;
- node *head;
-
- struct
- {
- int x;
- int y;
- } direction[4] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
-
- int map[ROW + 2][COL + 2] = {
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
- {1, 0, 0, 0, 0, 0, 0, 0, 1, 1},
- {1, 1, 1, 1, 0, 1, 1, 1, 1, 1},
- {1, 0, 0, 1, 0, 0, 1, 0, 1, 1},
- {1, 0, 1, 0, 0, 1, 1, 0, 1, 1},
- {1, 0, 1, 0, 1, 1, 1, 0, 1, 1},
- {1, 0, 1, 0, 0, 0, 0, 0, 1, 1},
- {1, 0, 0, 0, 1, 1, 1, 0, 1, 1},
- {1, 1, 1, 1, 1, 1, 1, 0, 2, 1},
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
- };
- int sign[ROW + 2][COL + 2] = {};
-
- void push(node *newNode)
- {
- node *p = head;
- while (p->next != NULL)
- {
- p = p->next;
- }
- p->next = newNode;
- }
-
- void quit()
- {
- while (head->next != NULL)
- {
- node *temp = head->next;
- head->next = temp->next;
- free(temp);
- }
- free(head);
- head = NULL;
- }
-
- void route()
- {
- node *p = head;
- while (p->next != NULL)
- {
- p = p->next;
- }
- p = p->prev;
- while (p->prev != NULL)
- {
- map[p->x][p->y] = 4;
- p = p->prev;
- }
- }
-
- int bfs(int x, int y)
- {
- int flag = 0;
-
- head = (node *)malloc(sizeof(node));
- head->next = NULL;
-
- node *start = (node *)malloc(sizeof(node));
- // 初始化 start 节点的父节点为 NULL 用于终止路径标记
- start->prev = NULL;
- start->x = x;
- start->y = y;
- start->step = 0;
- start->next = NULL;
-
- push(start);
- sign[x][y] = 1;
- map[x][y] = 5;
-
- node *prevNode = head;
- do
- {
- // 指向下一节点
- prevNode = prevNode->next;
- if (flag)
- continue;
-
- int i;
- for (i = 0; i < 4; ++i)
- {
- node *newNode = (node *)malloc(sizeof(node));
- // 记录父节点
- newNode->prev = prevNode;
- newNode->x = prevNode->x + direction[i].x;
- newNode->y = prevNode->y + direction[i].y;
- newNode->step = prevNode->step + 1;
- newNode->next = NULL;
- if (map[newNode->x][newNode->y] == 2)
- {
- flag = 1;
- // 终点节点入队
- push(newNode);
- break;
- }
- else if (sign[newNode->x][newNode->y] == 0 && map[newNode->x][newNode->y] == 0)
- {
- push(newNode);
- sign[newNode->x][newNode->y] = 1;
- map[newNode->x][newNode->y] = 3;
- }
- else
- free(newNode);
- }
- } while (prevNode->next != NULL);
- // 前进直至终点节点
-
- // 输出终点节点步数
- return prevNode->step;
- }
-
- int main()
- {
- // 便于之后高亮显示,否则会乱码
- system("cls");
-
- int i, j;
- for (i = 1; i <= ROW; ++i)
- {
- for (j = 1; j <= COL; ++j)
- {
- printf("%d ", map[i][j]);
- }
- putchar(10);
- }
- putchar(10);
-
- int MinStep = bfs(1, 1);
- // 标记最短路径
- route();
-
- if(MinStep)
- printf("Min step = %d\n", MinStep);
- else
- printf("Not Found!");
-
- for (i = 1; i <= ROW; ++i)
- {
- for (j = 1; j <= COL; ++j)
- {
- // 高亮显示路径
- if (map[i][j] == 4)
- printf(Green "%d " None, map[i][j]);
- else
- printf("%d ", map[i][j]);
- }
- putchar(10);
- }
-
- // 防止内存泄漏
- quit();
- return 0;
- }
BFS广度优先算法的实现要注意入队与出队时机、循环结束条件以及继续搜索条件。
试试看自己写一遍,想想如果想以矩形方式扩散搜索该怎么实现呢?(如下图)
(文中代码皆已经过编译运行)
文章为本人原创,创作不易,感谢支持!
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。