算法导论小结(9)-图的表示与搜索

By:             潘云登

Date:          2009-7-28

Email:         intrepyd@gmail.com

Homepage: http://blog.csdn.net/intrepyd

Copyright: 该文章版权由潘云登所有。可在非商业目的下任意传播和复制。

对于商业目的下对本文的任何行为需经作者同意。


写在前面

1.          本文内容对应《算法导论》(2)》第22章。

2.          主要介绍了图的两种表示方式(邻接表和邻接矩阵),以及广度优先搜索和深度优先搜索。

3.          希望本文对您有所帮助,也欢迎您给我提意见和建议。


图的表示

要表示一个图G=(V, E),有两种标准的方法,即邻接表和邻接矩阵。这两种表示法既可以用于有向图,也可以用于无向图(它们可以是加权图)。通常采用邻接表表示法,因为这种方法表示稀疏图(即|E|远小于|V|的平方)比较紧凑。但是,当遇到稠密图或必须很快判别两个给定顶点是否存在连接边时,通常采用邻接矩阵表示法。

²         邻接表

G=(V, E)的邻接表表示由一个包含|V|个列表的数组所组成,其中每个列表对应于V中的一个顶点。对于每一个uV,邻接表包含图G中所有和顶点u相邻的顶点(或者,它也可能包含指向这些顶点的指针)。对于加权图,可以将边的权值连同边一起存储在顶点的邻接表中。不论是有向图还是无向图,邻接表表示法都有一个很好的特性,即它所需要的存储空间为Θ(V+E)。不足在于,如果要确定图中边(u,v)是否存在,只能在顶点u的邻接表中搜索v

²         邻接矩阵

在图G=(V, E)的邻接矩阵表示法中,假定各顶点按某种任意的方式编号为1, 2, …, |V|,那么G的邻接矩阵为一个|V|*|V|的矩阵A=(aij),它满足:如果(i, j)Eaij=1;否则,aij=0。对于加权图,(i, j)边的权值可以简单地存储在aij中。一个图的邻接矩阵表示需要占用Θ(V2)的存储空间,而与图中的边数多少无关。


广度优先搜索

 

在给定图G=(V, E)和一个特定的源顶点s的情况下,广度优先搜索(BFSbreadth first search)首先会发现和s距离为k的所有顶点,然后才发现和s距离为k+1的其它顶点。该搜索算法能够生产一棵根为s、且包括所有s的可达顶点的广度优先树。对从s可达的任意顶点v,广度优先树中从sv的路径对应于图G中从sv的一条最短路径。如果u处于树中从根s到顶点v的路径中,那么u成为v的祖先,vu的后裔。BFS的总运行时间为O (V+E)

         为了记录搜索的轨迹,算法开始时,所有顶点都着成白色,随着搜索的进行,各顶点逐渐变成灰色,然后成为黑色。与黑色顶点相邻的所有顶点都是已经被发现的。灰色顶点可能会有一些白色的相邻顶点,它们代表了已发现和未发现顶点之间的边界。


深度优先搜索

在深度优先搜索(DFSdepth first search)中,对于新发现的顶点,如果它还有以此为起点而未探测到的边,就沿此边继续探测下去,当顶点v的所有边都已被探寻后,搜索将回溯到发现顶点v有起始点的那些边。DFS总运行时间也是O (V+E)

在深度优先搜索的同时,可以为每个顶点加盖时间戳。每个顶点v有两个时间戳:当顶点v第一次被发现并置为灰色时,记录下第一个时间戳d[v],当结束检查v的邻接表并置v为黑色时,记录下第二个时间戳f[v]。这样,在对一个有向或无向图G的任何深度优先搜索中,对于图中任意两个顶点uv,下述三个条件中仅有一个成立:1)区间[d[u],f[u]]和区间[d[v],f[v]]是完全不相交的,且uv都不是对方的后裔;2)区间[d[u],f[u]]完全包含于区间[d[v],f[v]]中,且uv的后裔;3)区间[d[v],f[v]] 完全包含于区间区间[d[u],f[u]]中,且vu的后裔。

     利用深度优先搜索,可以对一个有向无回路图进行拓扑排序,即各个顶点按照搜索完成时间f进行降序排列。其结果为该图所有顶点的一个线性序列,满足如果G包含边(u,v),则在该序列中,u就出现在v的前面。在很多应用中,拓扑排序用于说明事件发生的先后顺序。


附邻接表表示的图算法(

点此下载示例

#define WHITE 0

#define GRAY  1

#define BLACK 2

 

typedef struct link_node      /*邻接表中的结点*/

{

    int index;

    int weight;             /*边的权值*/

    struct link_node *next;

} lnode;

 

typedef struct vertex_node     /*实际顶点*/

{

    int data;

    int color;

    int index;

    lnode *link;

} vnode;

 

typedef struct graphic_queue

{

    int size;

    int head;

    int tail;

    void **array;

} queue;

 

typedef struct adjacency_list   /*邻接表表示的图*/

{

    int vertex_number;       /*顶点数*/

    int edge_number;        /*边数*/

    vnode *vlist;            /*存储所有顶点*/

    int *dtime;              /*搜索开始时间戳*/

    int *ftime;              /*搜索结束时间戳*/

    int *ancestor;            /*祖先顶点序号*/

    queue bfs_queue;         /*用于BFS的队列*/

    int time;                /*用于计算时间戳*/

} adjlist;

 

void new_graphic(adjlist *graphic, int vtx_number)

{

    int i;

 

    graphic->vertex_number = vtx_number;

    graphic->edge_number = 0;

    graphic->vlist = malloc(sizeof(vnode)*vtx_number);

    for(i=0; i<vtx_number; i++)

    {

          graphic->vlist[i].data = 0;

          graphic->vlist[i].color = WHITE;

          graphic->vlist[i].index = i;

          graphic->vlist[i].link = NULL;

    }

    graphic->dtime = malloc(sizeof(int)*vtx_number);

    graphic->ftime = malloc(sizeof(int)*vtx_number);

    graphic->ancestor = malloc(sizeof(int)*vtx_number);

    graphic->bfs_queue.size = vtx_number;

    graphic->bfs_queue.array = malloc(sizeof(void *)*vtx_number);

    graphic->bfs_queue.head = 0;

    graphic->bfs_queue.tail = 0;

}

 

void free_graphic(adjlist *graphic);

void set_vnode(adjlist *graphic, int index, int value);

 

void insert_edge(adjlist *graphic, int i, int j, int weight)

{

    lnode *new_lnode=NULL;

 

    new_lnode = malloc(sizeof(lnode));

    new_lnode->index = j;

    new_lnode->weight = weight;

    new_lnode->next = graphic->vlist[i].link;

    graphic->vlist[i].link = new_lnode;

    graphic->edge_number++;

}

 

void delete_edge(adjlist *graphic, int i, int j);

void print_graphic(adjlist *graphic);

void enqueue(queue *q, void *object);

void * dequeue(queue *q);

int is_queue_empty(queue *q);

 

void breadth_first_search(adjlist *graphic, int start)

{

    int i;

    vnode *ancestor_vnode=NULL, *child_vnode=NULL;

    lnode *temp_lnode=NULL;

 

    for(i=0; i<graphic->vertex_number; i++)

    {

          graphic->vlist[i].color = WHITE;

          graphic->dtime[i] = -1;

          graphic->ancestor[i] = -1;

    }

 

    graphic->vlist[start].color = GRAY;

    graphic->dtime[start] = 0;

    enqueue(&graphic->bfs_queue, (void *)&graphic->vlist[start]);

    while(!is_queue_empty(&graphic->bfs_queue))

    {

          ancestor_vnode = (vnode *)dequeue(&graphic->bfs_queue);

          temp_lnode = ancestor_vnode->link;

          while(temp_lnode != NULL)

          {

              child_vnode = &graphic->vlist[temp_lnode->index];

              if(child_vnode->color == WHITE)

              {

                  child_vnode->color = GRAY;

                  graphic->ancestor[child_vnode->index] = ancestor_vnode->index;

                  graphic->dtime[child_vnode->index]

                       = graphic->dtime[ancestor_vnode->index]+1;

                  enqueue(&graphic->bfs_queue, (void *)child_vnode);

              }

              temp_lnode = temp_lnode->next;

          }

          ancestor_vnode->color = BLACK;

    }

}

 

void depth_first_search(adjlist *graphic)

{

    int i;

 

    for(i=0; i<graphic->vertex_number; i++)

    {

          graphic->vlist[i].color = WHITE;

          graphic->ancestor[i] = -1;

    }

 

    graphic->time = 0;

    for(i=0; i<graphic->vertex_number; i++)

    {

          if(graphic->vlist[i].color == WHITE)

              dfs_visit(graphic, &graphic->vlist[i]);

    }

}

 

void dfs_visit(adjlist *graphic, vnode *v)

{

    lnode *temp_lnode=NULL;

 

    v->color = GRAY;

    graphic->time++;

    graphic->dtime[v->index] = graphic->time;

    temp_lnode = v->link;

    while(temp_lnode != NULL)

    {

          if(graphic->vlist[temp_lnode->index].color == WHITE)

          {

              graphic->ancestor[temp_lnode->index] = v->index;

              dfs_visit(graphic, &graphic->vlist[temp_lnode->index]);

          }

          temp_lnode = temp_lnode->next;

    }

    v->color = BLACK;

    graphic->time++;

    graphic->ftime[v->index] = graphic->time;

}

 

void print_bfs(adjlist *graphic);

void print_dfs(adjlist *graphic);

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值