BFS
2015-09-10 14:49
134 查看
总体描述
BFS 是最简单的图搜索算法之一。Prim最小生成树算法和Dijkstra的单源最短路径算法都使用了类似BFS的思想。
给定图G=(V, E)和一个可以识别的源节点s, BFS能够计算出从源点s到每个可以到达的节点的距离(最少的边数),同时生成一颗“BFS生成树“。
BFS的搜索过程是沿着其广度方向扩展的,算法需要在发现了所有距离源点s为k的所有节点之后,才会发现距离源节点s为k+1的其他节点。
为了跟踪算法进展,BFS在概念上将每个节点标识好颜色(白色:开始状态; 灰色:被发现,但是其邻接点还没有更新完,即邻接点还有白色的; 黑色:被发现,邻接点完全更新完)。
BFS对灰色和黑色节点加以区别,以确保搜索按照BFS模式进行。
执行BFS的过程,我们将构造出一颗BFS优先树。
最后打印BFS的路径时,我们可以根据生成树的“前驱-后继“状态来打印。
搜索过程:
假定输入图G = (V, E) 是以邻接链表所表示的,该算法为图中每个节点赋予了一些额外属性: 将每个节点u的颜色存放在属性u.color里,将u的前驱节点存放在属性u.pre之中,没有就记录为NIL。使用一个FIFO队列Queue管理灰色节点。伪代码如下(BFS过程,构造BFS树):
[code]BFS (G, s) { for each vertex {u} belongs to (G.V - {s}) u.color = WHITE u.d = INF u.pre = NIL s.color = GRAY s.d = 0 s.pre = NIL Q = NULL 空队列 ENQUEUE(Q, s) //s入队 while (Q != NULL) { u = DEQUEUE(Q) //出队 for each {v} belongs to (G.Adj[u]) //u的所有邻接节点 { if v.color == WHITE { v.color = GRAY v.d = u.d + 1 v.pre = u ENQUEUE(Q, v) //入队 } } u.color = BLACK } }
打印BFS路径,在BFS构造树之后:
[code]PRINT-PATH(G, s, v) { if v == s print s else if v.pre == NIL print "no path from " s " to " v "exists" else PRINT-PATH(G, s, v.pre) print v }
时间复杂度分析
邻接表存储时,BFS搜索的总运行时间为 O(V + E)实践
按照伪代码写demo,使用了邻接表存储,循环数组模拟队列即可。图是按照算法导论上的图 P345代码如下:
bfs.h
[code]#include <stdio.h> #include <stdlib.h> #define INF 10000 #define NIL 0 #define MAX 100 #define DATA char enum judge{ white = 0, gray = 1, black = 2 }; struct node { DATA name; DATA pre_node; size_t distance; enum judge color; }; struct G { struct node *array; struct vexnode *aja_table; struct graph *g; }; // =================== struct graph { size_t nodes_number; size_t edges_number; }; struct vexnode { DATA id; struct arcnode *arc_head; }; struct arcnode { DATA id; struct arcnode *next; };
bfs.c
[code]#include "./bfs.h" struct graph *generate_graph() { struct graph *head = NULL; if ((head = (struct graph *)malloc(sizeof(struct graph))) == NULL) return NULL; head->nodes_number = 0; head->edges_number = 0; return head; } struct arcnode *malloc_arcnode(const DATA id) { struct arcnode *tmp = NULL; if ((tmp = (struct arcnode *)malloc(sizeof(struct arcnode))) == NULL) return NULL; tmp->id = id; tmp->next = NULL; return tmp; } struct vexnode *malloc_vexnode(size_t length, struct graph *g) { struct vexnode *head = NULL; if ((head = (struct vexnode *)malloc(length * sizeof(struct vexnode))) == NULL) return NULL; g->nodes_number = length; return head; } void generate_vexnode(struct vexnode head[], struct graph *g) { /* * 做测试,id就用ABCDEFGH */ char data = 'A'; size_t length = g->nodes_number; struct vexnode *iter = head; for (size_t i = 1; i <= length; i++) { iter[i].id = data; iter[i].arc_head = NULL; data++; } } struct vexnode *search_vexnode_by_id(struct vexnode head[], const DATA id, struct graph *g) { size_t length = g->nodes_number; struct vexnode *first = head; for (size_t i = 0; i <= length; i++) { if (first[i].id == id) return (first + i); } return NULL; } int judge_arcnode_by_i_j(struct vexnode head[], const DATA i, const DATA j, struct graph *g) { struct vexnode *result = search_vexnode_by_id(head, i, g); if (result == NULL) return -1; //failure struct arcnode *iter = result->arc_head; while (iter != NULL) { if (iter->id == j) { return 0; //success } iter = iter->next; } return -2; //not find } int add_arcnode_by_i_j(struct vexnode head[], const DATA i, const DATA j, struct graph *g) { int judge = -3; if ((judge = judge_arcnode_by_i_j(head, i, j, g)) == 0) { printf("already exist.\n"); return -1; } struct vexnode *search = NULL; search = search_vexnode_by_id(head, i, g); if (search == NULL) { printf("could not search.\n"); return -1; } struct arcnode *insert = malloc_arcnode(j); insert->next = search->arc_head; search->arc_head = insert; g->edges_number++; return 0; } struct node *search_node_by_name(struct G *total, const DATA name) { size_t length = total->g->nodes_number; for (size_t i = 0; i < length; i++) { if (name == total->array[i].name) { struct node *position = total->array + i; return position; } } return NULL; } void BFS(struct G *total, const DATA s) { struct node *data_head = total->array; size_t length = total->g->nodes_number; for (size_t i = 0; i < length; i++) { if (data_head[i].name == s) { continue; } data_head[i].distance = 0; data_head[i].pre_node = NIL; data_head[i].color = white; } struct node *the_start = total->array; while (the_start->name != s) { the_start++; } if (the_start == NULL) { printf("failed to find the start point.\n"); return ; } the_start->distance = 0; the_start->pre_node = NIL; the_start->color = gray; // begin DATA Queue[MAX] = {0}; size_t top, end; //top做入队, end做出队 top = end = 0; Queue[top] = s; // enqueue top = (top + 1) % MAX; while (top != end) { // Queue is not empty DATA u = Queue[end]; //出队 end = (end + 1) % MAX; printf("start: u = %c\n ", u);/////////////////////// struct node *search_u = NULL; if ((search_u = search_node_by_name(total, u)) == NULL) { printf("search u error\n"); return; } struct vexnode *ajacency = search_vexnode_by_id(total->aja_table, u, total->g); struct arcnode *arc_start = ajacency->arc_head; //printf("search vexnode by id: find %c\n", ajacency->id); //getchar(); while (arc_start != NULL) { DATA v = arc_start->id; struct node *search_v = search_node_by_name(total, v); if (search_v == NULL) { printf("search v error\n") ; return ; } if (search_v->color == white) { search_v->distance = search_u->distance + 1; search_v->pre_node = search_u->name; search_v->color = gray; Queue[top] = v; //enqueue top = (top + 1) % MAX; printf("enqueue v = %c\n", v); } arc_start = arc_start->next; } //getchar(); } } void print_bfs(struct G *total, const DATA s, const DATA v) { struct node *search_v = search_node_by_name(total, v); if (search_v == NULL) { printf("print_bfs: could not find v\n") ; return; } if (s == v) printf("%c ", s); else if (search_v->pre_node == NIL) printf("no path from %c to %c \n", s, v); else { print_bfs(total, s, search_v->pre_node) ; printf("%c ", v); } } int main(void) { struct graph *g = generate_graph(); struct vexnode *head = malloc_vexnode(8, g); generate_vexnode(head, g); // add data here add_arcnode_by_i_j(head, 'A', 'B', g); add_arcnode_by_i_j(head, 'B', 'A', g); add_arcnode_by_i_j(head, 'B', 'C', g); add_arcnode_by_i_j(head, 'C', 'B', g); add_arcnode_by_i_j(head, 'A', 'D', g); add_arcnode_by_i_j(head, 'D', 'A', g); add_arcnode_by_i_j(head, 'D', 'E', g); add_arcnode_by_i_j(head, 'E', 'D', g); add_arcnode_by_i_j(head, 'D', 'F', g); add_arcnode_by_i_j(head, 'F', 'D', g); add_arcnode_by_i_j(head, 'E', 'F', g); add_arcnode_by_i_j(head, 'F', 'E', g); add_arcnode_by_i_j(head, 'E', 'G', g); add_arcnode_by_i_j(head, 'G', 'E', g); add_arcnode_by_i_j(head, 'F', 'G', g); add_arcnode_by_i_j(head, 'G', 'F', g); add_arcnode_by_i_j(head, 'F', 'H', g); add_arcnode_by_i_j(head, 'H', 'F', g); add_arcnode_by_i_j(head, 'H', 'G', g); add_arcnode_by_i_j(head, 'G', 'H', g); struct G *total = NULL; if ((total = (struct G *)malloc(sizeof(struct G))) == NULL) return -1; total->aja_table = head; total->g = g; if ((total->array = (struct node *)malloc(g->nodes_number * sizeof(struct node))) == NULL) return -1; //initialize DATA temp = 'A'; for (size_t j = 0; j < total->g->nodes_number; j++) { total->array[j].name = temp; temp++; } BFS(total, 'A'); print_bfs(total, 'A', 'G'); return 0; }
结果, 输入:A~G
[code]A D F G
相关文章推荐
- Android 4.4音量键控制音量流程
- SVN学习笔记11 -- Eclipse 中 SVN的相关操作 -- checkout and update
- Product of Array Except Self 数组除自身的所有乘积
- MongoDB—运维技术
- SQL Server 2012中的AlwaysOn尝试
- Win10 PIN密码开机登录如何设置 正确取消win10 pin登录密码图文教程
- Java获取客户端真实IP
- .Net中webBrowser控件指定IE版本
- Gtest学习笔记1.0
- sql 当前时间跟数据库字段做比较
- ZigZag Conversion
- 使用PowerShell调用MTools分析MongoDB性能并发送邮件
- Raid 原理及创建软raid
- C# 队列Queue
- 两个链表的第一个公共结点
- Android中onMeasure方法详解
- VS2010折叠大纲快捷键
- android4.4 PowerManagerService流程分析
- [LeetCode 213] House Roober II
- 图形用户界面:通过ip获取地址并显示天气情况