图的存储结构 - 链式前向星、邻接表

图的定义和术语总结

图按照有无方向分为有向图无向图。有向图由顶点和构成。无向图由顶点构成。弧有弧尾弧头之分。
无向图顶点边数叫做度,有向图顶点分为入度出度

图的存储结构

图的存储只影响遍历方式和效率。

邻接矩阵(Adjacency Matrix)

简单、好理解。但点的数量不能太多,n≤1000n≤1000n1000
无向图中,顶点 viv_ivi 的度为在邻接矩阵中第 iii 行(或第 iii 列)的元素之和。
有向图中,顶点 viv_ivi 的出度为在邻接矩阵中第 iii 行的元素之和,顶点 viv_ivi 的入度为在邻接矩阵中第 iii 列的元素之和。
带权图中,一般初始化为 ∞\infty,表示没有边。
nnn 个顶点和 eee 条边的无向图的创建,时间复杂度为 O(n+n2+e)O(n+n^2+e)O(n+n2+e),其中初始化邻接表耗费 O(n2)O(n^2)O(n2)

在无向图中,还有一种「半矩阵」的存储方式,用上三角(或下三角)+ 主对角线 压缩存储的一维数组方式。
一个 n×nn\times nn×n 的邻接矩阵可以被压缩到 n(n+1)2\frac{n(n+1)}{2}2n(n+1) 个元素。

邻接表(Adjacency List)

上述邻接矩阵对于边数较少顶点较多的图会产生极大浪费。
我们把数组与链表相结合的存储方式成为邻接表。
邻接表一般用ArrayList<ArrayList<Integer>> 维护。最常用。
nnn 个顶点和 eee 条边的无向图的创建,时间复杂度为 O(n+e)O(n+e)O(n+e)

链式前向星

静态版的邻接表,时空效率更极致。
本质上是用链表实现的邻接表,从点映射到第一条边,再在 nextnextnext 数组上跳跃。这个链表使用头插法维护的。
headheadhead 数组:起点→映射第一条边起点 \xrightarrow{\text{映射}} 第一条边起点映射第一条边
nextnextnext 数组,边→映射当前边的后继边 \xrightarrow{\text{映射}} 当前边的后继映射当前边的后继
tototo 数组:边→映射当前边的终点边 \xrightarrow{\text{映射}} 当前边的终点映射当前边的终点
核心代码如下:

// 把握住头插法的流程
// head[u] 和 cnt 的初始值为 -1
public static void add(int u, int v, int w) {
	next[++cnt] = head[u];
	head[u] = cnt
	to[cnt] = v;
	weight[cnt] = w;
}

// 遍历所有点
for (int u = 1; u <= n; u++) {
	System.out.print(u + "(邻居、边权) : ");
	// 遍历 u 的出边
	for (int i = head[u]; i != -1; i = next[i]) { // c++ 可以用 ~i 用于表示 i != -1
		System.out.print("(" + to[i] + "," + weight[i] + ") ");
	}
	System.out.println();
}

headheadhead 数组长度为点的数量
next、to、weightnext、to、weightnexttoweight 数组长度为边的数量,如果是无向图则需要边的数量x2。

#atom

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值