数据结构-图(存储结构-邻接矩阵与邻接表)-C语言

图是一种复杂的数据结构,顶点之间的逻辑关系错综复杂,因此图的存储结构也分多种,由于图是由顶点和边或弧这两部分组成,所以将这两部分合到一个结构中比较困难。所以我们使用两个结构去存储图这种结构。这里主要介绍两种基本的存储结构,即邻接矩阵与邻接表。
在这里插入图片描述

邻接矩阵

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

无向图

若图中有n个顶点,则邻接矩阵是一个n*n的二维数组,定义为
在这里插入图片描述
举例示意图如下:
在这里插入图片描述可知:
1.我们要判定任意两顶点是否有边无边就观察这两顶点的交叉点是1还是0。
2.我们要知道某个顶点的度,其实就是这个顶点在邻接矩阵中第i行(或第i列)的元素之和。比如顶点B的度就是1+0+1+0=2。
3.求顶点的所有邻接点就是将矩阵中第i行元素扫描一遍。
4.无向图的邻接矩阵是一个对称矩阵。

有向图

举例示意图如下:
在这里插入图片描述
可知:
1.一个顶点的入度为这个顶点所在列的各数之和,出度为这个顶点所在行的各数之和。eg:A的入度为0+0+0+1=1;出度为0+1+0+0=1。
2.判断顶点Ai 到Aj 是否存在弧,只需要查找矩阵中arc[i][j]
是否为1即可。
3.要求Ai的所有邻接点(Ai邻接到Aj)就是将矩阵第i行元素扫描一遍,查找arc[i][j]为1的顶点。

网图

若网图中有n个顶点,则邻接矩阵是一个n*n的二维数组,定义为:
在这里插入图片描述

举例示意图如下:
在这里插入图片描述
网图与无向图或有向图的定义方式不同罢了,分析方法同上。

代码

//*****图——邻接矩阵*******
#include <stdio.h>
#include <stdlib.h>

typedef char datatype;
typedef int edgetype;
#define MAXVEX 20					//顶点最大数,由使用者自定义 
#define INFINITY 65535 				//代指无限大 
typedef struct
{
	datatype data[MAXVEX];			//顶点表 
	edgetype arc[MAXVEX][MAXVEX];	//存储边或弧的权的邻接矩阵 
	int numVertexes,numEdges;		//顶点数,边或弧的个数 
}MGraph;//图结构--邻接矩阵

void Creat_MGraph(MGraph *G);
int main()
{
	MGraph G;
	Creat_MGraph(&G);
	int i,j;
	//将边表进行输出检查
	printf
	for(i=0;i<G.numVertexes;i++)
	{
		for(j=0;j<G.numVertexes;j++)
			printf("%10d",G.arc[i][j]); 
		printf("\n");
	}
}
//使用图的邻接矩阵存储方式创建网图  无向网图
void Creat_MGraph(MGraph *G)
{
	int a,b,i,j;
	int x,y;
	datatype ch;
	edgetype w;
	
	printf("Please input numVertexes,numEdges:");
	scanf("%d,%d",&a,&b);	//a:顶点个数 , b:边或弧的个数
	G->numVertexes=a;
	G->numEdges=b;
	//初始化邻接矩阵 
	for(i=0;i<a;i++)
	{
		for(j=0;j<a;j++)
		{
			if(i==j)
				G->arc[i][j]=0;
			else 
		 		G->arc[i][j]=INFINITY;
		}
	}
	//给每个顶点赋值 
	for(i=0;i<a;i++)
	{
		printf("Please input data[%d]:",i);
		scanf(" %c",&ch);
		G->data[i]=ch;
	}
	//给每条边或弧赋值 
	for(i=0;i<b;i++)
	{
		printf("Please input (vi,vj)的下标,和对应的权:\n");
		scanf(" %d,%d,%d",&x,&y,&w);
		G->arc[x][y]=w; 
		G->arc[y][x]= G->arc[x][y]; // 若为无向图,矩阵对称。否则删除即可 
	}
	//n:顶点数,e:边数 时间复杂度O(n^2+n+e)--------->O(n^2) 
}

输出结果:
在这里插入图片描述

邻接表

邻接矩阵是不错的一种图存储结构, 但是我们也发现,对于边数相对顶点较少的图,这种结构是存在对存储空间的极大浪费的。于是我们考虑对边或弧使用链式存储的方式,这样的话,不管有多少边,也不会存在空间浪费问题。

这种数组与链表相结合的存储方法称为邻接表(Adjacency List)。

邻接表的处理办法是这样。
1.图中顶点用一个一维数组存储,当然,顶点也可以用单链表来存储,不过数组可以较容易地读取顶点信息,更加方便。另外,对于顶点数组中,每个数据元素还需要存储指向第一个邻接点的指针,以便于查找该顶点的边信息。
在这里插入图片描述
2.图中每个顶点的所有邻接点构成一个线性表, 由于邻接点的个数不定,所以用单链表存储,无向图称为顶点的边表,有向图则称为顶点作为弧尾的出边表。.
在这里插入图片描述

无向图

在这里插入图片描述

有向图

在这里插入图片描述

网图

在这里插入图片描述
其实只要这些结构图能够被我们画出来,那么我们也会更清晰直观的理解两种存储结构。

代码

//*****图——邻接表*******
#include <stdio.h>
#include <stdlib.h>

typedef char datatype;
typedef int edgetype;
#define MAXVEX 20	

typedef struct ENode
{
	int adjvex;				//当前顶点的邻接点在顶点表中的下标 
	edgetype w;				//权数 
	struct ENode *next;		//指向下一个邻接点 
}EdgeNode;//边表结构 

typedef struct VNode
{
	datatype data;
	EdgeNode *firstedge;	//当前顶点的第一个邻接点,边表头指针 
}VertexNode,AdjList[MAXVEX];//顶点结构 

typedef struct
{
	AdjList adjList;		//储存所有的顶点的数组 
	int numVertexes,numEdges;//图中顶点数,边或弧的个数  
}GraphAdjList;//图结构--邻接表 

void Creat_GraphAdjList(GraphAdjList *G);
int main()
{
	GraphAdjList G;
	Creat_GraphAdjList(&G);
}
//使用图的邻接表存储方式创建网图  无向网图
void Creat_GraphAdjList(GraphAdjList *G)
{
	int v_num,e_num;
	int i,x,y;
	EdgeNode *e;
	datatype ch;
	edgetype w;
	
	printf("Please input numVertexes,numEdges:");
	scanf("%d,%d",&v_num,&e_num);	//顶点个数 , 边或弧的个数
	G->numVertexes=v_num;
	G->numEdges=e_num;
	//给每个顶点赋值 
	for(i=0;i<v_num;i++)
	{
		printf("Please input adjList[%d].data:",i);
		scanf(" %c",&ch);
		G->adjList[i].data=ch;
		G->adjList[i].firstedge=NULL;
	}
	//建立边表 
	/*建立有向图时,输入一次下标时
	只需将其中一个顶点作为弧尾或弧头的形式 进行建立边表
	不用管另一个顶点的边也要反向建立*/
	for(i=0;i<e_num;i++)
	{
		printf("Please input (vi,vj) or <vi,vj>的下标,和对应的权:\n");
		scanf(" %d,%d,%d",&x,&y,&w);
		e=(EdgeNode*)malloc(sizeof(EdgeNode));
		e->adjvex=y;
		e->w=w;
		e->next=G->adjList[x].firstedge;	//以头插法的形式将边插入到边表中 
		G->adjList[x].firstedge=e;
		
		e=(EdgeNode*)malloc(sizeof(EdgeNode));
		e->adjvex=x;
		e->w=w;
		e->next=G->adjList[y].firstedge;
		G->adjList[y].firstedge=e;
	}
	//n:顶点数,e:边数 时间复杂度--------->O(n+e) 
	
 	//打印邻接表
    printf("邻接表为:\n");
    for(i=0;i<G->numVertexes;i++){
        e=G->adjList[i].firstedge;
        while(e){
            printf("(%c,%c)",G->adjList[i].data,G->adjList[e->adjvex].data);
            e=e->next;
        }
        printf("\n");
    } 
}

输出结果:
在这里插入图片描述
画图不易啊、画图不易啊、画图不易啊!!!!
在这里插入图片描述不足之处,还请批评指正。
十字链表法传送门

  • 40
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值