前提:理解好什么是前向星?参照上一篇博客,然后看本文,会有所帮助
第二次更新讲解的内容
- head[]数组保存的是当前边的起点u 在边集数组中的位置
- next表示的是下一条边的位置,那么如何保存呢?我们并不是保存所有的边数,只是保存下一边的位置,和链表非常类似,所以就是链式,这就是点题
- 但是和我们常见的链式不太一样,我们是从后向前找,所以需要在更新head的时候,需要先记录下上一条边的位置,所以代码部分
e[cnt].next = head[u]; head[u] = cnt++; 是先保存next,在更新数值,然后递归输出结果
- 所以有了下面的代码
- 刷题目熟悉技巧,重中之重了
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 10000;
struct Edge
{
int u, v, w ,next;
}e[maxn];
int head[maxn],cnt =1;//统计边的数据
void addEdge(int u, int v, int w){
e[cnt].u = u;
e[cnt].v = v;
e[cnt].w = w;
e[cnt].next = head[u];
head[u] = cnt++;
}
void finde(int k)
{
if(k != -1)
{
cout << e[k].u << " " << e[k].v << " " << e[k].w << endl;
finde(e[k].next);
}
}
int main()
{
int n, m; cin >> n >> m;
memset(head,-1,sizeof(head));
for(int i = 1;i <= m;i++)
{
int x, y, z; cin >> x >> y >> z;
addEdge(x,y,z);
}
//接下来开始输出
for(int i = 1;i <= n;i++){
//输出head[i]为起点的所有的边数
if(head[i] != -1)
{
cout << "i: " << i << endl;
finde(head[i]);
}
}
return 0;
}
// 5 7
// 1 2 1
// 2 3 2
// 3 4 3
// 1 3 4
// 4 1 5
// 1 5 6
// 4 5 7
链式前向星
- 前向星:使用前向星的head[i]数组表示方法,但不排序。
- head[i]:表示边集的序号
- 链式:head[i] 表示以i为起点对应的边集中的编号,每次更新i的时候,将之前保存的数值,放入next中保存,这就有了寻找的踪迹,和并查集查找父节点的方式一样
- 综合起来就是链式前向星
链式前向星的插入
int cnt ; // 记录边数
int head[maxn]; // 记录边集对应的边的位置
void addedge(int u, int v, int w)
{
edge[cnt].to = v;
edge[cnt].w = w;
//保存着以起点u对应着的上一边表的 在边集中的位置,从而实现递归查找
edge[cnt].next = head[u];
//保存的是起点u最后对应的边数,所以是最大的
head[u] = cnt++;//更新u对应的边,因为可能很多条,所以先之前的给保存,然后更新
}
难点:
- next含义:表示与当前起点相同的边的下一条边 对应着的在 边集中的位置
- head[u] :保存的就是 在边集中对应的文字
- 可以和并查集查找父节点 不进行路径压缩的方式相同, 所以输出的时候可以采用递归函数写
链式前向星的寻找
方法一:采用递归查找(从后往前或者从前往后)
void find(int u, int k) //u:表示起点 ,k 表示在边集中的标号
{
//正序
if(k==-1)
return;
find(u,edge[k].next);
cout << u << " " << edge[k].to << " " << edge[k].w << endl;
}
//逆序
void find(int u, int k)
{
if(k!=-1)
{
find(u,edge[k].next);
cout << u << " " << edge[k].to << " " << edge[k].w << endl;
}
}
方法二:从后向前找
for(int j = head[i] ;j != -1;j = edge[j].next)
{
cout << i << " " << edge[j].to << " " << edge[j].w << endl;
}
链式前向星完整代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
////#define LOCAL
using namespace std;
//链式前向星:
// 前向星:不排序,但是head[i]:表示边集的序号
// 链式:head[i] 表示以i为起点对应的序号,每次更新i的时候,将之前保存的数值放在next中保存
// 这就有了寻找的踪迹,和并查集查找父节点的方式一样
const int maxn = 1000;
struct Edge
{
int next, to, w; // to:终点 next:以i为起点的下一条边的位置 w:权值
}edge[maxn];
int cnt ; // 记录边数
int head[maxn]; // 记录边集对应的边的位置
void addedge(int u, int v, int w)
{
edge[cnt].to = v;
edge[cnt].w = w;
//保存着以起点u对应着的上一边表的 在边集中的位置,从而实现递归查找
edge[cnt].next = head[u];
//保存的是起点u最后对应的边数,所以是最大的
head[u] = cnt++;//更新u对应的边,因为可能很多条,所以先之前的给保存,然后更新
}
void find(int u, int k)
{
if(k==-1)
return;
find(u,edge[k].next);
cout << u << " " << edge[k].to << " " << edge[k].w << endl;
}
int main()
{
int n, m;
cin >> n >> m;
//一开始所有的head都设置为-1,
memset(head,-1,sizeof(head));
for(int i = 1; i <= m;i++)
{
int u, v, w;
cin >> u >> v >> w;
addedge(u,v,w);
//双向
// addedge(v,u,w);
}
//开始输出
for(int i = 1;i <= n;i++)
{
cout << i << endl;
//j:表示的当前点对应的边集中的标号,标号保存着对应的终点以及下一条同起点的编号
// find(i, head[i]);
// cout << endl;
for(int j = head[i] ;j != -1;j = edge[j].next)
{
cout << i << " " << edge[j].to << " " << edge[j].w << endl;
}
cout << endl;
}
return 0;
}
// 5 7
// 1 2 1
// 2 3 2
// 3 4 3
// 1 3 4
// 4 1 5
// 1 5 6
// 4 5 7