数据结构之图的链表表示
本代码完全来自于http://blog.chinaunix.net/uid-24774106-id-3505579.html
代码写的非常专业,同时也有一些非常巧妙的思想,例如如何在不确定图顶点数目的情况动态分配,同时还能二分查找
贴上全部代码,供大家赏阅
代码包含两个文件,头文件graph.h和一个cpp文件
graph.h内容如下
#ifndef __GRAPH_H__ #define __GRAPH_H__ typedef struct graph *Graph; Graph graph_create(int n); void graph_destroy(Graph); void graph_add_edge(Graph, int source, int sink); int graph_vertex_count(Graph); int graph_edge_count(Graph); int graph_out_degree(Graph, int source); int graph_has_edge(Graph, int source, int sink); void graph_foreach(Graph g, int source, void (*f)(Graph g, int source, int sink, void *data), void *data); #endif
project1.cpp文件内容如下
// project1.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <stdlib.h> #include <assert.h> #include "graph.h" /* 代码摘自一位yale前辈 */ struct graph { int vexnum; /* number of vertices */ int edgenum; /* number of edges */ struct successors { int size; /* number of successors,即出度数*/ int capacity; /* number of slots in array,出度数组的长度,当空间不够,它就会两倍增加*/ char is_sorted; /* true if list is already sorted */ int list[1]; //出度数组,为什么只有一个元素还是用数组?是为了实现动态增加 } *alist[1];//alist数组相当于顶点链表,n个顶点就有n个元素,这里同样是为了动态增加 }; /* create a new graph with n vertices labeled 0..n-1 and no edges */ Graph graph_create(int n) { Graph g; int i; //新增一个graph空间和n-1个successors指针,算上graph中的一个successors指针就有n个了 g = (Graph)malloc(sizeof(struct graph) + sizeof(struct successors *) * (n-1)); //程序中大量使用assert,其作用是如果它的条件返回错误,则终止程序执行 assert(g); g->vexnum = n; g->edgenum = 0; for(i = 0; i < n; i++) { //顶点链表 g->alist[i] = (graph::successors*)malloc(sizeof(struct graph::successors)); assert(g->alist[i]); g->alist[i]->size = 0; g->alist[i]->capacity = 1; g->alist[i]->is_sorted= 1; //g->alist[i]->list[1]暂不确定 } return g; } /* free all space used by graph */ void graph_destroy(Graph g) { int i; for(i = 0; i < g->vexnum; i++) free(g->alist[i]); free(g); } /* 为graph添加边,这里是单向边,仅<u,v> */ void graph_add_edge(Graph g, int u, int v) { assert(u >= 0); assert(u < g->vexnum); assert(v >= 0); assert(v < g->vexnum); /* do we need to grow the list? */ while(g->alist[u]->size >= g->alist[u]->capacity) { g->alist[u]->capacity *= 2;//容量两倍增加的方式 g->alist[u] =(graph::successors*)realloc(g->alist[u], sizeof(graph::successors) + sizeof(int) * (g->alist[u]->capacity - 1)); } /* now add the new sink */ g->alist[u]->list[g->alist[u]->size++] = v; g->alist[u]->is_sorted = 0; /* bump edge count */ g->edgenum++; } /* return the number of vertices in the graph */ int graph_vertex_count(Graph g) { return g->vexnum; } /* return the number of vertices in the graph */ int graph_edge_count(Graph g) { return g->edgenum; } /* return the out-degree of a vertex */ int graph_out_degree(Graph g, int source) { assert(source >= 0); assert(source < g->vexnum); return g->alist[source]->size; } /* when we are willing to call bsearch,二分查找 */ #define BSEARCH_THRESHOLD (10) static int intcmp(const void *a, const void *b) { return *((const int *) a) - *((const int *) b); } /* return 1 if edge (source, sink) exists), 0 otherwise */ int graph_has_edge(Graph g, int source, int sink) { int i; assert(source >= 0); assert(source < g->vexnum); assert(sink >= 0); assert(sink < g->vexnum); //如果该顶点出度数超过10,才使用二分查找 if(graph_out_degree(g, source) >= BSEARCH_THRESHOLD) { if(! g->alist[source]->is_sorted) { qsort(g->alist[source]->list, g->alist[source]->size, sizeof(int), intcmp); } /* call bsearch to do binary search for us */ return bsearch(&sink, g->alist[source]->list, g->alist[source]->size, sizeof(int), intcmp) != 0; } else { /* just do a simple linear search */ /* we could call lfind for this, but why bother? */ for(i = 0; i < g->alist[source]->size; i++) { if(g->alist[source]->list[i] == sink) return 1; } /* else */ return 0; } } /* invoke f on all edges (u,v) with source u */ /* supplying data as final parameter to f */ //这里注意回调函数的使用 void graph_foreach(Graph g, int source, void (*f)(Graph g, int source, int sink, void *data), void *data) { int i; assert(source >= 0); assert(source < g->vexnum); for(i = 0; i < g->alist[source]->size; i++) { f(g, source, g->alist[source]->list[i], data); } } #define TEST_SIZE (6) //static使得本函数本文件可见 static void match_sink(Graph g, int source, int sink, void *data) { assert(data && sink == *((int *) data)); } //这个函数有什么用? static int node2dot(Graph g) { assert(g != NULL); return 0; } static void print_edge2dot(Graph g,int source, int sink, void *data) { fprintf(stdout,"%d->%d;n",source,sink); } //打印所有的边 static int edge2dot(Graph g) { assert(g != NULL); int idx = 0; int node_cnt = graph_vertex_count(g); for(idx = 0;idx<node_cnt; idx++) { graph_foreach(g,idx,print_edge2dot,NULL); } return 0; } int graph2dot(Graph g) { fprintf(stdout,"digraph{"); node2dot(g); edge2dot(g); fprintf(stdout,"}n"); return 0; } int _tmain(int argc, _TCHAR* argv[]) { Graph g; int i; int j; g = graph_create(TEST_SIZE); assert(graph_vertex_count(g) == TEST_SIZE); /* check it's empty */ for(i = 0; i < TEST_SIZE; i++) { for(j = 0; j < TEST_SIZE; j++) { assert(graph_has_edge(g, i, j) == 0); } } /* check it's empty again */ for(i = 0; i < TEST_SIZE; i++) { assert(graph_out_degree(g, i) == 0); graph_foreach(g, i, match_sink, 0); } /* check edge count */ assert(graph_edge_count(g) == 0); //添加边<u,v>,if u<v for(i = 0; i < TEST_SIZE; i++) { for(j = 0; j < TEST_SIZE; j++) { if(i < j) graph_add_edge(g, i, j); } } for(i = 0; i < TEST_SIZE; i++) { for(j = 0; j < TEST_SIZE; j++) { assert(graph_has_edge(g, i, j) == (i < j)); } } assert(graph_edge_count(g) == (TEST_SIZE*(TEST_SIZE-1)/2)); //打印图 graph2dot(g); /* free it * */ graph_destroy(g); return 0; }