您的位置:首页 > 其它

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: