数据结构--图的定义和存储结构

图的定义

图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成。注意:在图结构中,不允许没有顶点,在定义中,如果V是顶点的集合,则强调了顶点集合V的有穷非空。

在图中,若不存在顶点到其自身的边,且同一条边不重复出现,则称这样的图为简单图。

图的存储结构

邻接矩阵

考虑到图是由顶点和边或者弧两部分组成的。合在一起比较困难,那就自然地考虑到分两个结构来分别存储。顶点不分大小、主次,所以用一个一位数组来存储是很不错的选择。而边或者弧是顶点与顶点之间的关系,一维搞不定,那就考虑用一个二维数组来存储。

《数据结构--图的定义和存储结构》

对于带权值的图,可以令不可达的边的权值为无穷大。利用这个无穷大代表两个顶点不可达。

 邻接矩阵结构代码

//为了简单,默认顶点为int类型,也就是v0,v1,v2等的那个下标
//权值为int类型

#define MAXVEX 100
#define INF 65535

typedef struct
{
	int vexs[MAXVEX];
	int arc[MAXVEX][MAXVEX];

	int numVertexes, numEdges;
}MGraph;

  

无向图的创建代码:

void CreateMGraph(MGraph *G)
{
	//k为循环变量
	int k = 0;
	//i,j代表顶点的下标
	int i = 0;
	int j = 0;

	printf("读取顶点和边的数目...\n");
	scanf("%d,%d", &G->numVertexes, &G->numEdges);

	//输入顶点信息
	printf("读取顶点信息...\n");
	for(k = 0; k < G->numVertexes; k++)
	{
		scanf("%d", &G->vexs[k]);
	}

	//初始化所有的边为无穷大
	for(i = 0; i < G->numVertexes; i++)
	{
		for(j = 0; j < G->numVertexes; j++)
		{
			G->arc[i][j] = INF;
		}
	}//for


	int weight = 0;
	//获取权值的输入值
	printf("读取边(vi,vj)中两个顶点的下表i、j和对应的权值...\n");
	for(k = 0; k < G->numEdges; k++)
	{
		scanf("%d,%d,%d", &i, &j, &weight);

		G->arc[i][j] = weight;
		G->arc[j][i] = weight;
	}//for

}//CreateMGraph()

  无向图的边的二维数组是一个对称矩阵,有向图的创建更加简单。

测试代码:

void main(void)
{
	freopen("in.txt", "r", stdin);
	MGraph mGraph;
	MGraph *pMGraph = &mGraph;
	CreateMGraph(pMGraph);

	fclose(stdin);

	return;
}

试验数据:

//in.txt
4,5
0
1
2
3
0,1,10
0,2,2
0,3,7
1,2,8
2,3,5

 邻接表

回忆在树的存储结构中,降到了一种孩子表示法,将这种数组与链表相结合的存储方法称为邻接表。

《数据结构--图的定义和存储结构》

注意上图的数组称为顶点表,链表为边表结点。

 对于有向图,其实更加简单,但是有向图的每一个顶点分为入度和出度。

《数据结构--图的定义和存储结构》

《数据结构--图的定义和存储结构》

邻接表结构代码:

#define MAXVEX 100

typedef struct EdgeNode 
{
	int adjvex;
	int weight;//边的权重,用int表示
	struct EdgeNode *next;
}EdgeNode;

typedef struct VertexNode
{
	int data;
	EdgeNode *firstEdge;
}AdjList;

typedef struct
{
	AdjList adjList[MAXVEX];
	int numVertexs;
	int numEdges;
}AdjGraph;

  

邻接表创建有向图代码:

void CreateAdjGraph(AdjGraph *G)
{
	//统一规定,k用作循环变量
	int k = 0;

	printf("读取顶点和边数目...\n");
	scanf("%d%d", &G->numVertexs, &G->numEdges);
	
	printf("读取顶点...\n");
	for(k = 0; k < G->numVertexs; k++)
	{
		scanf("%d", &G->adjList[k].data);
		G->adjList[k].firstEdge = NULL;
	}
	
	printf("读取边信息...\n");
	//i,j用作表示顶点的下表,weight表示边的权重
	int i = 0;
	int j = 0;
	int weight = 0;

	for(k = 0; k < G->numEdges; k++)
	{
		scanf("%d%d%d", &i, &j, &weight);
	
		EdgeNode *pEdgeNode = (EdgeNode*)malloc(sizeof(EdgeNode));
		pEdgeNode->adjvex = j;
		pEdgeNode->weight = weight;
		pEdgeNode->next = NULL;

		//采用头插法,将这个边节点插入
		pEdgeNode->next = G->adjList[i].firstEdge;
		G->adjList[i].firstEdge = pEdgeNode;

/*无向图插入边信息

		//对于无向图,这里要再次插入
		EdgeNode *pEdgeNode = (EdgeNode*)malloc(sizeof(EdgeNode));
		pEdgeNode->adjvex = i;
		pEdgeNode->weight = weight;
		pEdgeNode->next = NULL;

		//采用头插法,将这个边节点插入
		pEdgeNode->next = G->adjList[j].firstEdge;
		G->adjList[j].firstEdge = pEdgeNode;
*/


	}
	
}//CreateAdjGraph

  在插入边表结点的时候,采用头插法更加简单一些。

测试代码:

void main(void)
{
	freopen("in.txt", "r", stdin);

	AdjGraph adjGraph;
	AdjGraph *pAdjGraph = &adjGraph;
	CreateAdjGraph(pAdjGraph);

	fclose(stdin);
}

  

测试数据:

//in.txt
10 19
0 1 2 3 4 5 6 7 8 9
0 1 4
0 2 1
0 3 3
2 3 1
1 4 9
1 5 8
2 4 6
2 5 7
2 6 8
3 5 4
3 6 7
4 7 5
4 8 6
5 7 8
5 8 6
6 7 6
6 8 5
7 9 7
8 9 3

 

    原文作者:stemon
    原文地址: https://www.cnblogs.com/stemon/p/4596128.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞