CMU 15122:Transitioning to C
Graph Representation
Graph Interface
Graph是Undirected的(15122定义),也就是说对于vertex A和B,BA和AB是一条edge。我们将graph表示成一个data structure,其中vertex定义为无符号整数。那么一个基本的graph interface可以如下所示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36typedef unsigned int vertex;
typedef struct graph_header *graph_t;
graph_t graph_new(unsigned int numvert);
//@ensures \result != NULL;
void graph_free(graph_t G);
//@requires G != NULL;
unsigned int graph_size(graph_t G);
//@requires G != NULL;
bool graph_hasedge(graph_t G, vertex v, vertex w);
//@requires G != NULL;
//@requires v < graph_size(G) && w < graph_size(G);
void graph_addedge(graph_t G, vertex v, vertex w);
//@requires G != NULL;
//@requires v < graph_size(G) && w < graph_size(G);
//@requires v != w && !graph_hasedge(G, v, w);
typedef struct neighbor_header *neighbors_t;
neightbors_t graph_get_neighbors(graph_t G, vertex v);
//@requires G != NULL && v < graph_size(G);
//@ensures \result != NULL;
bool graph_hasmore_neighbors(neighbors_t nbors);
//@requires nbors != NULL;
vertex graph_next_neighbor(neighbors_t nbors);
//@requires nbors != NULL;
//@requires graph_hasmore_neighbors(nbors);
void graph_free_neighbors(neighbors_t nbors);
//@requires nbors != NULL;
我们通过graph_hasmore_neighbors和graph_next_neighbors来检查或者获取某个vertex的相邻vertex。我们可以通过多种数据结构实现上面的interface,一个有e条边的graph可以被链表或者edge的数组来表示。在链表实现中,添加一个edge的时间复杂度是O(1),因为可以直接在链表前面接上。但是检查某一个edge是否存在需要O(e)的复杂度因为要遍历整个graph。获取某个节点的相邻节点同样需要O(e)的复杂度(Worst case)。使用哈希表和自平衡二分树也可以实现graph,但是这里只涉及到使用adjacency matrices和adjacency lists的graph实现。
Adjacency Matrices
我们可以使用一个二维数组储存两个节点之间是否存在edge,这样的表示方法在这里被称为Adjacency Matrices。假设我们有节点B(=1)和节点D(=3),我们检查两个节点之间是否存在edge的方法就是看二维数组的row 1,column 3。在一个不区分方向的图中,数组的右上半边是左下的镜像。因为edge的关系是对称的。因为我们不允许一个node使用edge链接自己,所以这个matrix的对角线是空的。
Adjacency Matrices的实现需要很多空间。对于一个有v个节点的graph我们需要$O(v^2)$的复杂度来分配内存。但是,使用改方法的好处是添加edge和检查edge的操作都是O(1)复杂度。
假如一个graph有0到$\frac{v(v-1)}{2}$个节点数v,并且多数edge存在,那么总edge数和$v^2$成比例关系,我们说这样的graph是dense的。对于dense graph,$O(e) = O(v^2)$,因此adjacency matrices是表示其的较好办法。因为存储其的空间并不比linked list多,但是操作更快。
Adjacency Lists
我们将dense graph的对立称作sparse graph。Adjacency lists适合作为sparse graph的实现。在这个实现当中,我们有一个类似于哈希表的一维数组,每一个vertex都在数组中有一个位置,并且数组中的每一个元素包含所有其他和该vertex相连的链表。
这个实现需要O(v + e)的空间来存储有v个vertex和e个edge的graph。也可以被写作O(max(v, e))。添加一个edge需要的时间是constant,但是lookup某一个edge需要的时间是O(min(v, e)),因为min(v-1, e)是每一个adjacency list的最大长度。在adjacency list实现里面寻找一个neighbor的时间是O(1)。
Implementation
1 | typedef struct adjlist_node adjlist |
Thanks for reading.