基于图(graph)的应用举例

 1、统计网络跳数

     图在解决许多与网络相关的问题时起到了重要的作用,统计在internet中从一个节点访问其他节点时中间必须经过的最小的节点数,这个消息在internet中非常有用,因为最明显的网络开销直接和所要的遍历的节点数目相关。

   下面是采用BFS实现计算网络跳数,使用了前面提供的队列及链表的函数接口。在阅读中希望先把链表和队列的相关的函数接口了解下。

  先了解下程序中几个结构体之间关系:(在写拓扑排序的时候,脑子一下子就乱了,不知道几个结构体之间的关系,特别绘制了下面的图,希望能对大家的理解有帮助)。


/*bfs.h
 *下面是关于图在网络跳数中的应用
 *采用广度优先的搜索方法
 * */
#ifndef BFS_H
#define BFS_H

#include "graph.h"
#include "list.h"

/*定义顶点的结构体体,在广度优先搜索*/
typedef struct BfsVertex_ {
    void *data;//指向图中顶点的数据的指针
    VertexColor color;//在搜索过程中维护顶点的颜色
    int hops;//维护从起始到顶点的跳数统计
}BfsVertex;

/*函数接口*/
int bfs(Graph *graph,BfsVertex *start,List *hops);

#endif

/*bfs.c*/
#include 
#include "../include/bfs.h"
#include "../include/graph.h"
#include "../include/list.h"
#include "../include/queue.h"

/***********************************************
 *广度优先搜索方法实现网络中两个节点之间的跳数
 *参数:graph:代表整个网络
 *      start:代表起始的顶点
 *      hops:返回的跳数链表
 *返回值:成功返回0,失败-1
 * *************************************************/
int bfs(Graph *graph,BfsVertex *start,List *hops)
{
    Queue queue;
    Adjlist *adjlist,
            *clr_adjlist;
    BfsVertex *clr_vertex,
              *adj_verex;
    ListElmt *element,
             *member;

    /*初始化图中所有的节点
     *当节点是起始节点vstart时,初始化成黑色,跳数为0;
     *其他初始化位白色,跳数为-1.
     * */
    for (element = list_head(graph->adjlists);element != NULL;element = list_next(element)){
        clr_vertex = ((Adjlist *)list_data(element))->vertex;
        if (graph->match(clr_vertex,start)){
            clr_vertex->color = gray;
            clr_vertex->hops = 0;   
        } else {
            clr_vertex->color = gray;
            clr_vertex->hops = 0;
        }
    }

    /*初始化队列*/
    queue_init(&queue,NULL);
    /*获得开始顶点的结构体,并加入到队列中*/
    if (graph_adjlit(graph,start,&clr_adjlist) != 0){
        queue_destroy(&queue);
        return -1;
    }
    if (queue_enqueue(&queue,clr_adjlist) != 0){
        queue_destroy(&queue);
        return -1;
    }

    /*BFS*/
    while (queue_size(&queue) > 0){
        /*得到队列中的首个节点元素*/
        adjlist = queue_peek(&queue);

        /*以此获得当前顶点的邻接顶点,并着色,和设置跳数*/
        for (member = list_head(&adjlist->adjacent);member != NULL; member = list_next(member)){
            /*获得顶点*/
            adj_verex = list_data(member);

            /*获得当前顶点的adjlist结构体*/
            if (graph_adjlit(graph,adj_verex,&clr_adjlist) != 0){
                queue_destroy(&queue);
                return -1;
            }
            clr_vertex = clr_adjlist -> vertex;

            /*设定顶点的颜色及跳数*/
            if (clr_vertex ->color == while ){
                clr_vertex -> color = gray;
                clr_vertex -> hops = ((BfsVertex *)adjlist -> vertex)->hops + 1;

                /*将当前顶点的adjlist 结构体加入队列*/
                if (queue_enqueue (&queue,clr_adjlist) != 0){
                    queue_destroy(&queue);
                    return -1;
                }
            }
        }
        /*在队列中将首个元素删除*/
        if (queue_dequeue (&queue, (void **)&adjlist) == 0)
            ((BfsVertex *)adjlist->vertex)->color = black;
        else {
            queue_destroy (&queue);
            return -1;
        }
    }
    /*以上已经将图的所有节点的跳数都已经加载上*/
    queue_destroy(&queue);
    /*下面室将所有跳数不为-1的顶点,保存到链表hops中*/
    list_init(hops,NULL);
    for (member = list_head(&adjlist->adjacent);member != NULL; member = list_next(member)){
        clr_vertex = ((Adjlist *)list_data(element)) -> vertex;
        if (clr_vertex->hops != -1 ){
            if (list_ins_next(hops,list_tail(hops),clr_vertex) != 0){
                list_destroy(hops);
                return -1;
            }
        }
    }
    return 0;

}

2 拓扑排序

      将有向无环图中的顶点按照现行的方式排列,使得所有的边都是从左向右的方式,拓扑排序的最通常的用途是在执行若干个互相之间有依赖关系的任务时,确定一种可接受的先后顺序。先看下面这个图:

 

/*dfs.h
 *下面是关于图在拓扑排序中应用
 *采用深度优先的搜索方法
 * */
#ifndef DFS_H
#define DFS_H

#include "graph.h"
#include "list.h"

/*定义顶点的结构体体,在广度优先搜索*/
typedef struct DfsVertex_ {
    void *data;//指向图中顶点的数据的指针
    VertexColor color;//在搜索过程中维护顶点的颜色
}DfsVertex;

/*函数接口*/
int dfs(Graph *graph,List *ordered);

#endif
/*dfs*/
#include 

#include "../include/dfs.h"
#include "../include/graph.h"
#include "../include/list.h"

static int  dfs_main(Graph *graph, Adjlist *adjlist, List *ordered)
{
    Adjlist *clr_adjlist;
    DfsVertex *clr_vertex,
              *adj_vertex;
    ListElmt *member;
    
    /*顶点着色*/
    ((DfsVertex *)adjlist->vertex) -> color = gray;

    for (member = list_head(&adjlist->adjacent); member != NULL; member = list_next(member)){
        /**/
        adj_vertex = list_data(member);
        if (graph_adjlist(graph,adj_vertex,&clr_adjlist) != 0)
            return -1;

        clr_vertex = clr_adjlist->vertex;

        if (clr_vertex->color == white){
            if (dfs_main(graph,clr_adjlist,ordered) != 0)
                return -1;
        }

        ((DfsVertex *)adj_vertex->vertex) ->color = black;

        if (list_ins_next(ordered,NULL,(DfsVertex *)adjlist->vertex) != 0)
            return -1;

        return 0;
}

/*******************************************************
 *参数:graph -> 图
 *      ordered -> 保存完成拓扑排序后返回的顶点列表
 * 函数成功返回0,失败-1;
 * ********************************************************/
int dfs(Graph *graph,List *ordered)
{
    DfsVertex *vertex;
    ListElmt *element;
    /*初始化图中所有的顶点*/
    for (element = list_head(&graph_adjlists(graph)); element != NULL; element = list_next(element)){
        vertex = list_data(element);
        vertex ->color = white;
    }
    
    /*初始化链表*/
    list_init(ordered,NULL);
    for (element = list_head(&graph_adjlists(graph)); element != NULL; element = list_next(element)){
        vertex = ((Adjlist *)list_data(element))->vertex;

        if (vertex ->color == white){
            if(dfs_main(graph,(Adjlist *)list_data(element),ordered) != 0){
                list_destroy(ordered);
                return -1;
            }
        }
    }
    return 0;
}



你可能感兴趣的:(【C语言学习】,C算法精解)