前向星:
前向星是一种特殊的边集数组,我们把边集数组中的每一条边按照起点从小到大排序,如果起点相同就按照终点从小到大排序,
并记录下以某个点为起点的所有边在数组中的起始位置和存储长度,那么前向星就构造好了.
用len[i]来记录所有以i为起点的边在数组中的存储长度.
用head[i]记录以i为边集在数组中的第一个存储位置.
(这样有了head和len就知道哪些下标的存储的信息是属于你想要的起点为i的边)
我们输入边的顺序为:
1 2
2 3
3 4
1 3
4 1
1 5
4 5
那么排完序后就得到:
编号: 1 2 3 4 5 6 7
起点u: 1 1 1 2 3 4 4
终点v: 2 3 5 3 4 1 5
得到:
head[1] = 1 len[1] = 3
head[2] = 4 len[2] = 1
head[3] = 5 len[3] = 1
head[4] = 6 len[4] = 2
但是利用前向星会有排序操作,如果用快排时间至少为O(nlog(n))
前向星 ----> 链式前向星 :本质上我们想要信息,排序不影响信息,但排序有时间消耗,消耗在确定哪些下标存储了特定i节点的信息上。于是我们可以通过一个索引一个下标找一个下标,这样可以避免掉排序需要的时间消耗,信息还是不变的。
链式前向星:
edge是用来记录信息的,下标之间没有关系,只是顺序。但要想找到以i为起点的边集数组 让他们建立联系,就得引入next来记录起点为i的上一条边的下标 也就是你想找i 然后通过head[i](最后一个输入的,编号最大的)可以找到所有与 i 相关的边集(for循环不断更新next下标获取上一次输入的与i有关的边的下标),从而通过下标找到与i点有关的所有边的想要的信息。
head[i]保存的是以i为起点的所有边中编号最大的那个,而把这个当作顶点i的第一条起始边的位置.
这样在遍历时是倒着遍历的,也就是说与输入顺序是相反的,不过这样不影响结果的正确性.因为你只需要信息。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1005;//点数最大值
int n, m, cnt;//n个点,m条边
struct Edge
{
int to, w, next;同起点的上一条边的编号
}edge[maxn];//边集
int head[maxn]; head[i],表示以i为起点的第一条边在边集数组的位置(编号)
void init()//初始化
{
for (int i = 0; i <= n; i++) head[i] = -1;
cnt = 0;
}
void add_edge(int u, int v, int w)//加边,u起点,v终点,w边权
{
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].next = head[u];与这个边起点相同的上一条边的编号
head[u] = cnt++; 更新以u为起点的最大编号,为了给下一个存nextedge的下标
}
int main()
{
cin >> n >> m;
int u, v, w;
init();//初始化
for (int i = 1; i <= m; i++)//输入m条边
{
cin >> u >> v >> w;
add_edge(u, v, w);//加边
/*
加双向边
add_edge(u, v, w);
add_edge(v, u, w);
*/
}
for (int i = 1; i <= n; i++)//n个起点
{
cout << i << 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;
}