看完绝不后悔超级详细!!!!
目录
邻接表的介绍
邻接表将每个节点的邻接关系以链表的形式记录下来。对于每一个节点,链表中存储了该节点所连接的其他节点。这个结构用来高效地存储图中的边关系通常用数组加链表的方式实现。
三大组件+idx指针:
h[i]
(记录每个节点的头指针,存储和 i
相邻的第一个节点在 e[]
中的位置)
e[idx]
(存储的是每一条边的终点节点)
ne[idx]
(存储链表中的下一个节点在 e[]
中的位置)
idx
:数组索引,一个指针变量,用来记录当前用了多少个数组位置。每当我们 插入一条边时,idx
会自增,用来标记邻接表中下一次插入的数组位置。
----这么看肯定很抽象ba。。。
举例:
h[1] = 0
,表示与节点 1
相邻的第一个节点可以通过 e[0]
找到。
e[0] = 2
,表示节点 1
与节点 2
相连。
ne[0] = 1
,则表示在 e[0]
之后,链表中的与节点1相邻的下一个节点可以通过 e[1]
找到。
e[1] = 3
,表示节点 1
除了与结点2还与节点 3 相连。
头插法构建邻接表模版 ※
void add(int a, int b) {
e[idx] = b; // e[idx] 存储边 a->b 的终点 b
ne[idx] = h[a]; // ne[idx] 记录当前链表的下一个节点(即原来的链表头)
h[a] = idx; // h[a] 更新为新的链表头,指向新的节点(即 idx 位置)
idx++; // 更新 idx,准备存储下一条边
}
调用add建树模版
memset(h ,-1 ,sizeof h) //初始化h为-1
for(int i=0;i<n-1;i++) // n个结点插n-1次构成树
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b),add(b,a); // 无向图a→b且b→a
}
举例:头插法完整的邻接表构建过程
树可以看作特殊的图
1
/ \
2 3
/ \
4 5
树的边为
1 - 2
2 - 1
1 - 3
3 - 1
2 - 4
4 - 2
2 - 5
5 - 2
每一条边(无向边)需要插入两次,一次是 a → b
,一次是 b → a
,构成双向连接。
插入边的步骤:
每一条边(无向边)需要插入两次,一次是 a → b
,一次是 b → a
,构成双向连接。
void add(int a, int b) {
e[idx] = b; // e[idx] 存储边 a->b 的终点 b
ne[idx] = h[a]; // ne[idx] 记录当前链表的下一个节点(即原来的链表头)
h[a] = idx; // h[a] 更新为新的链表头,指向新的节点(即 idx 位置)
idx++; // 更新 idx,准备存储下一条边
}
插入 1 → 2
和 2 → 1
:
e[0] = 2
,ne[0] = h[1]=-1
,h[1] =