16、图

来源:互联网 发布:淘宝手机下单减价 编辑:程序博客网 时间:2024/05/22 02:12

1、图作为一种模型来定义对象之间的关系。对象由顶点表示,而对象之间的关系则通过顶点之间的边来表示。

2、图分为有向图和无向图,有向图的边叫做弧。
这里写图片描述

3、图的表达式:G = (V, E),E包含有序对(u,v),对于无向图无所谓(u,v)和(v,u)。
如上图,有向图:V={v0, v1, v2, v3}. E={(v0,v1), (v2, v0), (v2, v3), (v3, v0)}.
无向图:V={v0, v1, v2, v3,v4}.E={(v0, v1), (v0, v3),(v1, v2), (v1, v4), (v2, v3), (v2, v4)}

4、图中两个重要关系:邻接、关联
邻接:有向图中(v0, v1)说明v1邻接v0。
完全图:一个图中每一个顶点都与其他顶点相邻接
关联:有向图中(v0, v1)说明边(v0, v1)从顶点v0关联到v1,顶点和边的关系。

5、顶点的入度:以该顶点为终点的边数。
顶点的出度:以该顶点为起点的边数。
简单路径:没有重复顶点的路径
环:路径包含相同的节点两次或以上,即从某点出发最后能返回到某点。

6、连通:每个顶点都能通过某条路径到达其他顶点。
关节点:移除某个顶点将使图或某分支失去连通性。
桥:移除某条边使得图失去连通性。

7、邻接表适用于稀疏图;邻接矩阵适用于稠密图

8、搜索方法:广度优先搜索、深度优先搜索
这里写图片描述

深度优先搜索
这里写图片描述

9、代码实现
这里写图片描述
(1)数据结构:每个顶点对应一个链表节点,节点中*data指向节点结构AdjList

//AdjList包含:顶点;与该顶点相连接的一个顶点集合。这是每个链表节点指向的数据datatypedef struct AdjList_{    void *vertex;    Set adjacent;}AdjList;//整个图的属性,包含:节点数、边数、所有节点组成的链表属性typedef struct Graph_{    int vcount;    int ecount;    int (*match)(const void *key1, const void *key2);    void (*destroy)(void *data);    List adjlists;}Graph;typedef enum VertexColor_{    white, gray, black}VertexColor;

(2)初始化

void graph_init(Graph *graph, int (*match)(const void *key1, const void *key2), void(*destroy)(void *data)){    graph->vcount = 0;    graph->ecount = 0;    graph->match = match;    graph->destroy = destroy;    list_init(graph->adjlists, 0, NULL, NULL, NULL);    return;}

(3)删除整个图

void graph_destroy(Graph *graph){    AdjList *adjlist;    while(list_size(&graph->adjlists) > 0)    {        if(list_rem_next(&graph->adjlists, NULL, (void **)&adjlist) == 0)        {            //删除每个顶点的邻节点集合            set_destroy(&adjlist->adjacent);            //删除该顶点,这两者就是链表节点指向的*data            if(graph->destroy != NULL)                graph->destroy(adjlist->vertex);            //释放*data指向结构自身的空间,上面为该空间指向的内容              free(adjlist);        }    }}

(4)插入一个顶点:申请一个AdjList,其中成员vertex为data,其边集set初始化为NULL

//这里入口参数*data对应 *adjlist中vertex int graph_ins_vertex(Graph *graph, const void *data){    LIST_ELEMENT *element;    AdjList *adjlist;    int retval;    for(element = list_tail(graph->adjlists); element != NULL; element = list_next(element))    {        if(graph->match(data, ((AdjList *)list_data(element))->vertex))            return 1;    }    if((adjlist = (AdjList *)malloc(sizeof(AdjList))) == NULL)         return -1;    adjlist->vertex = (void *)data;    set_init(&adjlist->adjacent, graph->match, NULL);    if((retval = list_ins_next(&graph->adjlists, list_tail(&graph->adjlists), adjlist)) != 0)        return retval;    graph->vcount++;    return 0;}

(5)插入一条边

//在图中加入一条连线 //对于图中已存在顶点data1和data2,单向data1指向data2,就是在顶点data1的集合中加入data2 int graph_ins_edge(Graph *graph, const void *data1, const *data2){    LIST_ELEMENT *element;    int retval;    //先找到顶点data2和data1     for(element = list_head(graph->adjlists); element != NULL; element = list_next(element))    {        if(graph->match(data2, ((AdjList *)list_data(element))->vertex))            break;    }    if(element == NULL)        return -1;    //向data1的集合中插入data2     if((retval = set_insert( &( (AdjList *)(list_data(element))->adjacent ), data2)) != 0 )     {        return retval;    }    graph->ecount++;}

(6)删除顶点,顶点不能和其他任何顶点相连,即不在其他节点的集合中,自己的集合为空。

int graph_rem_vertex(Graph *graph, void **data){    LIST_ELEMENT *element;    AdjList *adjlist;    int found;    prev = NULL;    found = 0;    for(element = list_head(graph->adjlists); element != NULL; element = list_next(element))    {        if(set_is_mumber(&( (AdjList *)(list_data(element))->adjacent ), *data))            return -1;        if(graph->match(*data,&( (AdjList *)(list_data(element))->vertex ))        {            temp = element;            fount =1;        }        //此处在for内部,如果没发现则prev一直在更新         if(!found)            prev = element;    }    if(!found)        return -1;    if(set_size( &((AdjList *)list_data(temp))->adjacent )> 0)        return -1;    *data = adjlist->vertex;    //此时节点集合为空可以直接释放     free(adjlist);    graph->vcount--;    return 0;} 

(7)删除边,即删除data1集合中的元素data2

int graph_rem_edge(Graph *graph, const void *data1, const *data2){    LIST_ELEMENT *element;    //先找到顶点data1     for(element = list_head(graph->adjlists); element != NULL; element = list_next(element))    {        if(graph->match(data1, ((AdjList *)list_data(element))->vertex))            break;    }    if(element == NULL)        return -1;    if(set_remove(&( (AdjList *)(list_data(element))->adjacent ), *data2)) != 0)        return -1;    graph->ecount--;    return 0;}

(8)找到某个顶点对应的结构adjlist

//data对应的结构返回到adjlist int graph_adjlist(const Graph *graph, const void *data, AdjList **adjlist){        LIST_ELEMENT *element, *prev;        prev = NULL;        for(element = list_head(graph->adjlists); element != NULL; element = list_next(element))        {            if(graph->match(*data,&( (AdjList *)(list_data(element))->vertex ))            {                break;            }            prev = element;        }        if(element == NULL)            return -1;        *adjlist = list_data(element);        return 0;}

(9)判断顶点data1和data2是否有邻接关系,即判断data2是否存在于data1的集合中

int graph_is_adjacent(const Graph *graph, const void *data1, const void *data2){        LIST_ELEMENT *element, *prev;        prev = NULL;        for(element = list_head(graph->adjlists); element != NULL; element = list_next(element))        {            if(graph->match(*data,&( (AdjList *)(list_data(element))->vertex ))            {                break;            }            prev = element;        }        if(element == NULL)            return -1;        return set_is_mumber(&( (AdjList *)(list_data(element))->adjacent ), data2);}
原创粉丝点击