牛马学习数据结构 第十天 ~ (邻接矩阵)

  邻接矩阵其实就是一个二维数组,用于表示图的一种方式,通常用作遍历图、检测连通性。

邻接矩阵的概念

由于图是中顶点和边(或弧)两部分组成的。顶点可以用一个一维的顺序表来存储,但是边(或弧)由于是顶点与顶点之间的关系,一维搞不定,所以可以考虑用一个二维的顺序表来存储,而二维的顺序表就是一个矩阵。对于一个有n个顶点的图 G,邻接矩阵是一个nxn的方阵(方阵就是行列数相等的矩阵)。对于邻接矩阵而言不需要去考虑是有向的还是无向的,统一都可以理解成有向的,因为有向图可以兼容无向图,对于无向图而言,只不过这个矩阵是按照主对角线对称的,因为 A到 B 有边,则必然 B 到 A有边。对带权图和无权图,邻接矩阵的表示略有差别。

无权图邻接矩阵


无权图的邻接矩阵对于一个 nxn图中,采用一个nxn的方阵 adi[n][n],在这样一个矩阵里:
1)矩阵的行和列都对应图中的一个顶点。
2)如果顶点 A到 顶点 B有一条边(这里是单向的),则对应矩阵单元为 1。
3)如果顶点 A到 顶点 B 没有边(这里同样是单向的),则对应的矩阵单元就为 0。例如,对于一个有四个顶点的无权图,首先需要有一个顺序表来存储所有的顶点的(A,B,C,D),图的邻接矩阵如下:

从这个矩阵中我们可以看出,A 能够到 B、D,B 能够到 A、C,C能够到 B、D,D能够到 A、C。如图所示:

 简单解释一下,对于矩阵的主对角线的值 adj[0][0]、adj[1][1]、adj[2][2]、adj[3][3]全为 0,因为这个图中,不存在顶点自己到自己的边,adj[0][1]=1 是因为A到 B的边存在,而 adj[2][0]=0 是是因为C 到A的边不存在。对于无向图而言,它的邻接矩阵是一个对称矩阵。
有了这个矩阵,我们就可以很容易地知道图中的信息,
1)我们要判定任意两顶点之间是否有边就非常容易。
2)我们要知道某个顶点的度,其实就是这个顶点在邻接矩阵中i行的元素之和。
3)求顶点i的所有邻接点就是将矩阵中第i行元素扫描一遍,arc[i]]为1就是邻接点。

带权图邻接矩阵

带权图的邻接矩阵在带权图的邻接矩阵中,每个短阵元素表示一个有向边的权值。如果不存在从一个节点到另一个节点的边,则通常将其表示为特殊的值,如0,-1或无穷。假设有一个有向带权图,它有4个顶点(A,B,C,D),边及其权重如下:
·边 A->B 的权重是3·边 A->C 的权重是7·边 B->A 的权重是4·边 B->D 的权重是1·边 C->D 的权重是2·边 D->A 的权重是1我们可以将这个有向带权图表示为以下的邻接矩阵:
AB C D
A0370
B4001
C0002
D1000
在这个矩阵中,行表示起始顶点,列表示目标顶点。短阵元素的值代表起始顶点到目标顶点的边的权重。如果没有边存在,我们用0来表示。例如,第一行表示从A到各点的边的权重,可以看出有从A到B的边,权重为3,有从A到C的边,权重为7,没有从A出发到达D的边,所以为0。
当然,什么情况下不能用0来代表边不存在的情况?
大多数情况下边权是正值,但个别时候真的有可能就是0,甚至有可能是负值。因此必须要用一个不可能的值来代表不存在。

邻接矩阵的优点


1)简单直观:邻接矩阵是一个二维顺序表,通过矩阵中的元素值可以直接表示顶点之间的连接关系,非常直观和
易于理解。
2)存储效率高:对于小型图,邻接矩阵的存储效率较高,因为它可以一次性存储所有顶点之间的连接关系,不需
要额外的空间来存储边的信息。
3)算法实现简单:许多图算法可以通过邻接矩阵进行简单而高效的实现,例如 遍历图、检测连通性等。


邻接矩阵的缺点


1)空间复杂度高:对于大型图,邻接矩阵的空间复杂度较高,因为它需要存储一个nxn的矩阵,这可能导致存
储空间的浪费和效率问题。
2)不适合稀疏图:邻接矩阵对于稀疏图(即图中大部分顶点之间没有连接)的表示效率较低,因为它会浪费大量
的存储空间来存储零元素。

#include <stdio.h>
#include <stdlib.h>

#define inf -1

typedef struct Graph{
	int vertices;
	int **edges;
}Graph;

void GraphCreate(Graph *g,int vertices){
	g->vertices = vertices;
	g->edges = (int**)malloc(sizeof(int*) * vertices);
	for(int i=0;i<vertices;++i){
		g->edges[i] = (int*)malloc(sizeof(int) * vertices);
		for(int j=0;j<vertices;++j){
			g->edges[i][j] = inf;
		}
	}
} 

void GraphDestor(Graph *g){
	for(int i=0; i<g->vertices;++i){
		free(g->edges[i]);
	}
	free(g->edges);
	g->edges = NULL;
}

void GraphAddedges(Graph *g,int u,int v,int w){
	g->edges[u][v] = w;
}

void GraphPrintf(Graph *g){
	for(int i=0 ;i<g->vertices;++i){
		for(int j=0; j<g->vertices;++j){
			printf("%d ",g->edges[i][j]);
		}
		printf("\n");
	}
}

int main(void){
	
	Graph a;
	
	GraphCreate(&a,4);
	
	GraphAddedges(&a,0,1,1);
	GraphAddedges(&a,0,3,1);
	GraphAddedges(&a,1,0,1);
	GraphAddedges(&a,1,2,1);
	GraphAddedges(&a,2,1,1);
	GraphAddedges(&a,2,3,1);
	GraphAddedges(&a,3,0,1);
	GraphAddedges(&a,3,2,1);
	
	GraphPrintf(&a);
	
	GraphDestor(&a);

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值