注:由于数据结构与算法分析上关于图的表述过于混乱,在此使用算法导论作为教材。由于二者关于细节处可能有所出入,因此对图进行重新学习。
1、图的表示。
对于图G(graph)=(V,E),有两种方法进行表示。
一、邻接矩阵。
二、邻接链表。
其中,邻接矩阵用于稠密图,即边的条数|E|接近|V|²的情形。而邻接链表通常用于稀疏图,即|E|<<|V|²的情形。在实际的应用中,对于邻接链表的运用远远大于对于邻接矩阵的运用。因此,接下来会对邻接链表进行描述和介绍。
对于图G=(V,E),其邻接链表表示由一个包含|V|条链表的数组Adj所构成,其中数组中的每个节点都由一条链表。对于每个节点u∈V,邻接链表Adj[u]包含所有与结点u之间有边相连的节点v。即以Adj[u]为表头的链表中包含指向与节点u有边相连的节点的指针。邻接链表的存储空间需求为Θ(V+E)。
由于邻接链表存储的方法是通过点之间十分存在边的关系,在伪代码中,我们就将数组Adj看作图的一个属性,即Adj是结构体G中的一个元素。
若G是有向图,对于边(u,v)来说,节点v出现在链表Adj[u]中,因此,所有邻接链表长度之和为|E|。
若G是无向图,对于边(u,v)来说,节点v会出现在链表Adj[u]中,同时节点u会出现在链表Adj[v]中,因此所有邻接链表长度之和为2|E|.
三、用邻接链表表示权重图。
回忆:权重图:图中的每条边都带有一个相关的权重图。其中的权重值通常由一个w:E->R的权重函数给出。
example: 对于权重函数w(u,v),我们能够直接将边(u,v)∈E的权重值通过w(u,v)放到节点u的邻接链表中。
邻接链表与邻接矩阵相比,也有一定的缺点:链表无法在短时间内判断边(u,v)是否是图中的边。因为邻接链表的方法只能通过一个for循环遍历以Adj[u]为头节点的链表进行判断。相反,邻接矩阵能够直接地通过判断adj[u][v]==0来进行判断。
四、邻接矩阵的运用。
在无向图中,邻接矩阵是一个对称矩阵,因为adj[u][v]和adj[v][u]都表示边(u,v)是否存在,所以二者相等,因此在存储无向图的时候,有一半的空间都是浪费了的,同时,该邻接矩阵也是一个对称矩阵。满足A=A^T,即矩阵A等于A的转置。因此,我们可以通过仅使用矩阵的左上半部分来存储数据,从而节约空间。
在权重图的表示中,我们则可直接将边(u,v)的权重存储在adj[u][v]中