图——图的存储结构(邻接矩阵和邻接表法)

图的五种存储结构:

1、图的邻接矩阵表示法

图是由顶点和边或弧两部分组成。图的邻接矩阵(Adjacency Matrix)存储方式是用两个数组表示图,一个一维数组存储图中的顶点信息,一个二维数组(邻接矩阵)存储图中边或弧的信息。

2、图的邻接表表示法

邻接矩阵是一种不错的图存储结构,但我们发现对于边数相对顶点较少的图,这种结构是存在对存储空间的极大浪费的。因此采用邻接表(Adjacency List)存储图结构,就是将数组和链表相结合的存储方法,数组存储图的顶点信息,图中每个顶点的所有邻接点用链表存储,链表的头结点就是该顶点。

3、图的十字链表表示法(有向图的邻接表优化存储结构)

对于有向图,邻接表是有缺陷的,可以通过邻接表很简单计算出度,但想了解入度就必须要遍历整个图才知道,反之,逆邻接表解决入度却不了解出度的情况。十字链表就是将邻接表和逆邻接表结合起来的一种图的存储结构。顶点表结点结构:data(数据域存储顶点信息)、fistin(指针域指向入度的第一个结点)、firstout(指针域指向出度的第一个结点);边表结点结构:tailvex(边的尾部起点结点的下标)、headvex(边的头部终点结点的下标)、headlink(指针域指向头部终点结点相同的下一条边)、taillink(指针域指向尾部起点结点相同的下一条边)、weight(边上的权值);

图——图的存储结构(邻接矩阵和邻接表法)_第1张图片

4、邻接多重边(无向图的邻接表优化存储结构)

对于无向图邻接表表示法只关注顶点操作(如计算顶点的度),如果我们关注边的操作,比如对已访问的边做标记或者删除一条边等操作,那就意味着需要找到这条边的两个边表结点进行操作,比较麻烦。因此提出邻接多重边的存储结构优化无向图的操作,它和无向图的十字链表结构相似,顶边表结点的结构:ivex、ilink、jvex、jlink。ivex和jvex是某条边依附的两个顶点的下标,指针域ilink指向依附顶点ivex的下一条边,指针域jlink指向依附顶点jvex的下一条边。

5、边集数组(关注边的操作,克鲁斯卡尔Kruskal算法中用到)

边集数组是由两个一维数组构成。一个是存储顶点信息;另一个是存储边的信息,这个边数组每个元素由一条边的起点下标begin、终点下标end、权值weight组成。显然边集数组关注的是边的集合,在边集数组中查找一个顶点的度需要扫描整个边数组,效率并不高。因此它更适合对边依次进行处理操作,而不适合对相关顶点的操作。

6、图的存储结构选择策略

图的五种存储结构中最重要的是邻接矩阵和邻接表,它们分别代表着边集是用数组还是链表的方式存储。十字链表是针对有向图邻接表结构的优化,邻接多重表是针对无向图邻接表结构的优化。边集数组更多考虑对边的关注,如求最小生成树Kruskal算法它的思想就是对边集基于并查集的贪心算法。用什么存储结构需要具体问题具体分析,通过稠密图或者读取数据较多,结构修改较少的图,用邻接矩阵更合适,反之则应该考虑邻接表。

#include
using namespace std;
#define MaxVex 100  //定义最大顶点数
#define Inf 65535  //定义无穷大
typedef char VertexType;  //定义顶点数据类型
typedef int EdgeType;  //定义边上权值数据类型


//邻接矩阵存储图的结构
typedef struct Graph
{
	VertexType vex[MaxVex];  //一维数组存储顶点信息
	EdgeType arc[MaxVex][MaxVex];  //二维数组存储边的权值信息,也就是邻接矩阵
	int numVex,numArc;  //记录图中当前顶点数、边数
}MatrixGraph;
//建立无向网图的邻接矩阵表示
void CreateMatrixGraph(MatrixGraph *G)
{
	int i,j,k,weight;
	//输入顶点数和边数
	cin>>G->numVex>>G->numArc;
	//输入顶点信息,建立顶点表
	for(i=0;inumVex;i++)
		cin>>G->vex[i];
	//初始化邻接矩阵
	for(i=0;inumVex;i++)
		for(j=0;jnumVex;j++)
			G->arc[i][j]=Inf;
	//输入边信息,建立邻接矩阵
	for(k=0;knumArc;k++)
	{
		cin>>i>>j>>weight;
		G->arc[i][j]=weight;
		G->arc[j][i]=G->arc[i][j];  //无向图,矩阵对称
	}
}
/*
*
*
*
*
*/
//邻接表存储图的结构
//边结点
typedef struct EdgeNode
{
	int vex;  //邻接点域,存储边另一个连接顶点对应的下标
	EdgeType weight;  //边的权值
	struct EdgeNode *next;  //指向下一个邻接点
}EdgeNode;
//顶点结点
typedef struct VexNode
{
	VertexType data;  //顶点域,存储顶点信息
	EdgeNode *firstEdge;  //边的头指针
}VexNode;
//邻接表存储所有顶点结点
typedef struct  
{
	VexNode adjList[MaxVex];  //adjList数组存储顶点结点
	int numVex,numArc;  //记录图中当前顶点数、边数
}AdjListGraph;
//建立无向图的邻接表结构
void CreateAdjListGraph(AdjListGraph *G)
{
	int i,j,k,w;
	EdgeNode *e;
	//输入顶点数和边数
	cin>>G->numVex>>G->numArc;
	//输入顶点信息,建立顶点表
	for(i=0;inumVex;i++)
	{
		cin>>G->adjList[i].data;  //输入顶点信息
		G->adjList[i].firstEdge=NULL;  //将边表置为空表
	}
	//输入边信息,建立边表
	for(k=0;knumArc;k++)
	{
		cin>>i>>j>>w;
		e=(EdgeNode*)malloc(sizeof(EdgeNode));
		e->vex=j;
		e->weight=w;
		//头插法链表插入边信息
		e->next=G->adjList[i].firstEdge;
		G->adjList[i].firstEdge=e;
		
		//无向图,另一个顶点同样的操作
		e=(EdgeNode*)malloc(sizeof(EdgeNode));
		e->vex=i;
		e->weight=w;
		//头插法链表插入边信息
		e->next=G->adjList[j].firstEdge;
		G->adjList[j].firstEdge=e;
	}
}
int main()
{
	MatrixGraph G1;
	AdjListGraph G2;
	CreateMatrixGraph(&G1);
	CreateAdjListGraph(&G2);
    cout<

 

你可能感兴趣的:(数据结构与算法分析)