5.3 图的矩阵表示

图的矩阵表示

前面在二元关系中学过,图可以使用矩阵表示。现在再来学习更多的矩阵表示方法。

关联矩阵

先来回顾一下关联的定义:

设e=(u,v)(<u,v>)是无向(有向)图G=<V,E>的一条边, 称u,v为e的端点,e与u ( v)关联。

无向图的关联矩阵

定义

定义 设无向图G=<V,E>, V={v1, v2, …, vn}, E={e1, e2, …, em}, 令mij为vi与ej的关联次数,称(mij)n*m为G的关联矩阵,记为M(G) 。

可以看出,关联矩阵考虑的是顶点和边的关系,每行表示顶点,每边表示列。

例子

在这里插入图片描述
上图的关联矩阵为

在这里插入图片描述

性质

可有如下性质:

(1) 每一列恰好有两个1或一个2;(每条边提供两个度,自环对同一个顶点提供2两个度)
(2) ∑ j = 1 m m i j = d ( v i ) , i = 1 , 2 , . . . , n \sum _{j=1}^{m}m_{ij}=d(v_i), i=1,2,...,n j=1mmij=d(vi),i=1,2,...,n;(每一行加起来就是对应顶点的度数,也就是关联总数)
(3) ∑ i , j m i j = 2 m \sum _{i,j}m_{ij}=2m i,jmij=2m;(全部加起来就是度数之和,根据握手定理,度数和为边数的两倍)
(4)Vi为孤立点当且仅当第i行全为0;(无边关联即为孤立点)
(5)平行边的列相同.(平行边两端点相同)

有向图的关联矩阵

定义

在这里插入图片描述

例子

在这里插入图片描述
在这里插入图片描述

性质

可得类似性质
(1) 每一列恰好有一个1和一个-1;(一条有向边提供一个出度,一个入度)
(2) 第i行1 的个数等于 d + ( v i ) d^+(v_i) d+(vi), -1 的个数等于 d − ( v i ) d^-(v_i) d(vi)
(3) 1的总个数等于-1的总个数, 且都等于m
(4) 平行边对应的列相同

有向图的邻接矩阵

定义

定义$ 设有向图 D = < V , E > , V = { v 1 , v 2 , … , v n } , E = { e 1 , e 2 , … , e m } , a i j ( 1 ) 为 顶 点 v i 邻 接 到 顶 点 v j 边 的 条 数 , ( a i j ( 1 ) ) n × n 称 为 D 的 邻 接 矩 阵 , 记 作 A ( D ) , 简 记 为 A D=<V,E>, V=\{v_1, v_2, …, v_n\}, E=\{e_1, e_2, …, e_m\}, a^{(1)}_{ij} 为顶点v_i邻接到顶点v_j边的条数,(a^{(1)}_{ij})_{n \times n} 称为D的邻接矩阵, 记作A(D), 简记为A D=<V,E>,V={v1,v2,,vn},E={e1,e2,,em},aij(1)vivj,(aij(1))n×nD,A(D),A
注意:这里定义为邻接到,即为始点指向终点的通路,不能反过来。

例子
在这里插入图片描述
在这里插入图片描述

性质

在这里插入图片描述
可见我们可以使用邻接矩阵表示通路长度。
我们前面在二元关系当中也学习过,矩阵的幂次可以表示关系的幂运算,也就是关系的复合,而关系的复合本质上是一种传递,那么这种传递可以表示为首尾相连的通路形式,也就是说,邻接矩阵A可以表示通路长度为1的通路,那么 A 2 = A × A A^2=A\times A A2=A×A可以表示通路长度为2的个数,那么. A 3 = A 2 × A A^3=A^2\times A A3=A2×A可以表示通路长度为3的通路个数

长度为l的通路表示

在这里插入图片描述
看个例子
在这里插入图片描述
在这里插入图片描述
其中简单验证一下我们也可知道,这里 A 2 = A × A A^2=A\times A A2=A×A A 3 = A 2 × A A^3=A^2\times A A3=A2×A, A 4 = A 3 × A A^4=A^3\times A A4=A3×A.
当然还有另外一种方法,就是直接在图中找长度为对应的通路个数。例如: A 2 A^2 A2里的第二行第一列元素,即为 v 2 v_2 v2 v 1 v_1 v1通路长度为2(通路经过2条边)的个数,为3条。值得注意,这里的自环可以循环灵活使用
在这里插入图片描述

那么在这里我们可以解决类似以下的问题:

(1) 长度为1, 2, 3, 4的通路各有多少条?其中回路分别为多少条?
(2) 长度小于或等于4的通路为多少条?其中有多少条回路?

将对应矩阵里面的元素直接求和即可

长度 通路 回路
1 8 1
2 11 3
3 14 1
3 17 3
合计 50 8
其中回路为特殊的通路(自己到自己的通路)

有向图的可达矩阵

定义

在这里插入图片描述
可达矩阵描述的是一种连通性,强调的是通路的存在,并不在意通路的长度是多少,这里一定要和邻接矩阵区别开。

例子

在这里插入图片描述
在这里插入图片描述

稀疏矩阵的快速转置算法主要分为两种:行逐行转置和列逐列转置。其中,行逐行转置的算法复杂度较低,但是对于稀疏矩阵来说,由于矩阵中非零元素的分布不均匀,会导致算法的效率较低。因此,我们这里介绍列逐列转置的算法。 算法5.3的基本思想是,先扫描一遍原矩阵,确定每一列非零元素的个数,在转置后的矩阵中确定每一行的起始位置。然后再扫描一遍原矩阵,将每一个非零元素转置到转置后的矩阵中对应的位置。 具体实现过程如下: 1. 定义结构体Node,表示稀疏矩阵的非零元素: ``` typedef struct { int row; // 非零元素所在的行 int col; // 非零元素所在的列 int val; // 非零元素的值 } Node; ``` 2. 定义转置函数transpose: ``` void transpose(Node *a, Node *b, int m, int n) { int *num = (int*)malloc((n+1)*sizeof(int)); // num数组用于记录每一列的非零元素个数 memset(num, 0, (n+1)*sizeof(int)); for (int i = 0; i < m; i++) { num[a[i].col]++; // 统计每一列的非零元素个数 } int *cpot = (int*)malloc((n+1)*sizeof(int)); // cpot数组用于记录每一行的起始位置 cpot[0] = 0; for (int i = 1; i <= n; i++) { cpot[i] = cpot[i-1] + num[i-1]; } for (int i = 0; i < m; i++) { int j = cpot[a[i].col]++; b[j].row = a[i].col; b[j].col = a[i].row; b[j].val = a[i].val; } } ``` 3. 在主函数中调用transpose函数: ``` int main() { int m = 5, n = 4; // 原矩阵的大小 Node a[6] = {{0, 0, 1}, {0, 3, 2}, {1, 1, 3}, {3, 0, 4}, {3, 2, 5}, {4, 3, 6}}; // 原矩阵的非零元素 Node b[6]; // 转置后的矩阵 transpose(a, b, 6, n); printf("转置前的矩阵:\n"); for (int i = 0; i < 6; i++) { printf("(%d,%d,%d)\n", a[i].row, a[i].col, a[i].val); } printf("转置后的矩阵:\n"); for (int i = 0; i < 6; i++) { printf("(%d,%d,%d)\n", b[i].row, b[i].col, b[i].val); } return 0; } ``` 上述代码中,我们假设原矩阵5行4列,非零元素分别为(0,0,1)、(0,3,2)、(1,1,3)、(3,0,4)、(3,2,5)、(4,3,6),然后调用transpose函数进行转置,最后输出转置前后的矩阵
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小邹子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值