有向图需要用十字邻接表来表示。但用链表实现十字邻接表是非常苦恼的,代码很容易便会达到数百行。事实上有一种数组实现十字邻接表,不用指针便可解决有向带权图的问题(含重边,自环)。 理论上有向图解决了,无向图也可以被解决。
输入格式
4 5
1 4 9
4 3 8
1 2 5
2 4 6
1 3 7
输入时点也可以是点的名称,此时需要建立点的名称字符串与点号的映射表。
方法解读
i 号点的第一条边边号为 first[i];
i 号边的出点的下一条边边号为 next[i];
特点
① 以边号为主要操作对象。 寻找边的方法是在表中先得到边号,再用u、v、w数组由边号得到边的信息。
② 反序入表。 各个边在表中的排列顺序与读入顺序恰相反,这是因为每次插入新边都是在链头而非链尾插入。
③ 放弃数组[0]位置。 为了建立起边号、点号与索引的直接对应关系,建议直接从[1]开始使用。
注:
点号指的是读入时代表点的数字(从多少开始计由输入决定,甚至无需连续。但超大数组大小需能保证容纳所有点号,也可先把点号视作字符串名称记录再建立点号与字符串名称的映射表);
边号指的是读入时该边是第几个读入的边(从1开始计)。
基本操作实现
0. InitialGraph
//全局变量 ps:我也不想这么野蛮 我也是被带坏的
int u[5000005], v[5000005], w[5000005]; //边的信息
int first[5000005], next[5000005]; //threads
bool flag[5000005]; //边是否被访问
//图的初始化:
for (i = 1; i <= M; i++) {
first[i] = -1;
flag[i] = false;
}
1. BuildGraph
有向图:
for (i = 1; i <= N; i++) { // i = 1 开始 弃置数组[0]位置
scanf("%d %d %d", &u[i], &v[i], &w[i]);
next[i] = first[u[i]];
first[u[i]] = i;
}
无向图:
for (i = 1; i <= N; i++) { // i = 1 开始 弃置数组[0]位置
scanf("%d %d %d",&u[i],&v[i],&w[i]);
next[i] = first[u[i]];
first[u[i]] = i;
//对 i + N 做一遍刚才所做的事 且u v互换(反向) (N是边数)
v[i + N] = u[i]; u[i + N] = v[i]; w[i + N] = w[i];
next[i + N] = first[u[i + N]];
first[u[i + N]] = i + N;
}
2. 遍历 i 号点的所有边
有向图:
k = first[i]; // k 初始化为第一条边边号
while (k != -1) {
...
...
k = next[k]; // k 更新为下一条边边号
}
3.遍历全图所有边(对所有点,遍历点的所有边)
for (i = 1; i <= n; i++) { // i = 1 开始 弃置数组[0]位置
k = first[i];
while (k != -1)
{
...
...
k = next[k];
}
}
(图源https://www.cnblogs.com/codingmengmeng/p/5645073.html)