图的存储结构

原文链接http://blog.csdn.net/midgard/article/details/4076619

图,无向图G = (V, E)有向图 G = <V, E> V是点集vertex, E是边集edge
图通常有两种存储方法。
  • 邻接矩阵, 多用于稠密图,记录每两个顶点之间边的信息。空间复杂度是O(|V|2);通常实际问题稠密图情况很少。
  • 邻接表, 是表示图的标准方法,尤其对于稀疏图节省很多存储空间,空间复杂度是O(|E|+|V|). 对于每个顶点,使用一个表存放所有邻接的顶点。
邻接矩阵容易理解就不介绍了,邻接表实现方法:
(1)使用vector或list
(2)使用map,将key设为顶点,值设为邻接表。
(3)使用Vertex类,顶点即为Vertex的实例,将邻接表作为Vertex的成员函数。
下面一步一步介绍如何用代码实现邻接表结构来存储图,主要体会为什么需要这些信息。
首先,从邻接表的定义中直观的看出需要有顶点信息,对于每个顶点一定存储了数据信息,邻接顶点信息。而对于邻接顶点结构,一定存储了next邻接顶点信息。即:
struct adjVertexNode
{
adjVertexNode* next;
}
struct VertexNode
{
char* data;//以结点存储的信息为字符为例。
adjVertexNode* list; //邻接点链表。
}
一个图结构便可以由结点数组组成。考虑到数组不能用变量声明大小。所以预先给定一个足够大的数组。当然也可以用vector,List实现,那是后话了。同时图必须要包含顶点数量信息。
#define MAX_VERTEX_NUM 20
struct Graph
{
VertexNode VertexNode[MAX_VERTEX_NUM];
int vertexNum;
}
以上,是我们尝试构建一个图的存储结构必须,也是一定应该会想到的信息。
接下来,对于adjVertexNode结构体, 由于它明显是个链表,很容易会考虑里面是不是应该有数据信息呢?否则只有一个链没有意义。
于是很容易想到写成存邻接顶点数据信息:
struct adjVertexNode
{
char* data;
adjVertexNode* next;
}
而恰恰这是最容易出现的错误写法!!!事实上这个数据信息已在顶点VertexNode结构体中体现了,完全没有必要这样重复写出来。
回过头仔细看一下定义:对于每个顶点,使用一个表存放所有邻接的顶点。也就是说,存放的数据一定是标识邻接顶点的信息。但又不能重复存放定点数据信息。
因为一个图邻接表表示法需要一个存储顶点的数组,所以这里应该存放顶点位置信息,也就是每个顶点在顶点数组中的位置信息。即:
struct adjVertexNode
{
int adjVertexPosition;
adjVertexNode* next;
}
务必要理解这一点,如果还是有点晕,那先记住他,到后面实现拓扑排序时,会看到为什么要存储位置信息。
另外,对于拓扑排序,起始点是从一个入度为0的顶点开始,所以入度信息必须包含在顶点结构体中。于是:
struct VertexNode
{
char* data;//以结点存储的信息为字符为例。
adjVertexNode* list; //邻接点链表。
int indegree;
}
至此,得到了一组图需要的较为完整的结构体信息,至少完成拓扑排序所需要的信息足够了。
#define MAX_VERTEX_NUM 20
struct adjVertexNode
{
int adjVertexPosition;
adjVertexNode* next;
}
struct VertexNode
{
char* data;//以结点存储的信息为字符为例。
adjVertexNode* list; //邻接点链表。
int indegree;
}
struct Graph
{
VertexNode VertexNode[MAX_VERTEX_NUM];
int vertexNum;
}
还有一些其他信息,比如边上的权值(可以存储在adjVertexNode中),图的边数,类型(可以存储在Graph中),这里没有添加,主要是避免混淆。当真正理解每个元素信息为什么需要时再做扩展。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章