图不同于树和线性表的存储, 图的存储主要存储顶点和边弧信息,而其中顶点又不分主次,没有顺序,但是任意两个顶点之间都有可存在着边弧或者相关的权值信息相联系起来。基于这样的特性,我们也无法将图顶点之间的关系通过物理内存连续的方式表现出来,这一点线性表就很有优势的表现出来了。图的存储结构大体上分为两种:1> 侧重体现边或者弧相关信息的存储方式,2>侧重保存顶点相关信息的。
这里介绍图的邻接矩阵存储方式,邻接矩阵存储理解简单,在实际使用中也是比较常用的一种图存储操作方式。
图的邻接矩阵用两个数组来表示图, 一个一维数组来存储顶点信息, 另外一个二维数组存储顶点之间的边圈关系
比如有一个图如下所示
无向图的邻接矩阵存储结构
这里有图的两个顶点之间有连通就用1表示,否则就用0表示,我们设置了两个数组vertex[4] = {v0, v1, v2, v3}, map[4][4] = {{0, 1, 1, 1}, {1, 0, 1, 0}, {1, 1, 0, 1}, {1, 0, 1, 0}};
vertex数组就是对所有顶点的存储, 而map数组则是各个顶点之间的关系,比如map[1][2] = 1, 则表示顶点v1到顶点v2之间有连通,通过这种方法存储图结构,我们还可以方便的求得每个顶点的度, 而主对角线则是各自顶点到自己的连通情况,没有单一环路的时候必须全是0。
上图是一个无向图,对于一个无向图的邻接矩阵,上下部分是对称的(很容易看出来map[i][j] == map[j][i]),所以对于无向图的邻接矩阵可以用上三角或者下三角进行保存,这样可以节省存储空间,对于有向图有出入之分,所以不一定是上下对称的情况。但是利用邻接矩阵也能很好的进行存储。有向图的邻接矩阵存储如下所示:
有向图的邻接矩阵存储结构
针对带有权值的网图来说,邻接矩阵的存储唯一的不同在于将非网图的连通情况换成对应的边权值,使得美元权值的边设置为一个可以区分的数值(比如正无穷,负无穷等)即可,其余的操作上没有什么区别。
网图的邻接矩阵存储结构
邻接矩阵结构定义如下所示:
typedef int VertexType;
typedef int EdgeType;
#define MAXVEERTEX 100
#define MAXINFO 0x7FFFFFFF
typedef struct graph
{
VertexType vertexs[MAXVEERTEX];
EdgeType edges[MAXVEERTEX][MAXVEERTEX];
int vertex_num, edge_num;
}Graph;
void init_graph(Graph* g)
{
for (int k = 0; k < g->vertex_num; k++)
g->vertexs[k] = k;
for (int i = 0; i < g->vertex_num; i++)
for (int j = 0; j < g->vertex_num; j++)
g->edges[i][j] = MAXINFO;
}
int create_graph(Graph* g)
{
cout << "Input graph vertexs and edges :" << endl;
cin >> g->vertex_num >> g->edge_num;
init_graph(g);
for (int i = 0; i < g->vertex_num; i++)
{
for (int j = 0; j < g->vertex_num; j++)
{
cout << "Input edge info for vertex[" << i << "] to vertex[" << j << "]" << endl;
cin >> g->edges[i][j];
}
}
return 0;
}