理解前向星
定义:
参照来源: (https://blog.youkuaiyun.com/acdreamers/article/details/16902023)
前向星:
- 对所有输入的边的集合,进行排序。 按照起点、终点、权值进行排序
- 需要保存边的开始位置、其实位置、权重
- head[i]: 以i为起点的边在已经排好序的边集数组中的位置
- len[i]: 以i为起点的边的个数
重新思考前向星后的理解
- 前向星主要是和邻接表一样,用来保存每个节点后面有多少条边,并记录下个数以及该节点在边集数组中的位置
- 边集数组:数据保存的时候是在一个数组中,所以在数组中是有位置的,排好序之后,位置更加明显
- 举例说明:
5 7
1 2 1
2 3 2
3 4 3
4 1 5
1 5 6
4 5 7
1 3 4
head: 1 len = 3
1 2 1
1 3 4
1 5 6
head: 4 len = 1
2 3 2
head: 5 len = 1
3 4 3
head: 6 len = 2
4 1 5
4 5 7
- 其中可以看见,只要排好序之后,节点有点的边数就是依次对应的
- 所以head[i]表示的就是当前节点在排好数组中的位置在哪里,如果为-1就表示当前节点是没有的子节点的
- len[i]表示当前节点的子节点的个数有多少个
- 和邻接表是类似的,不过呢其中是需要排序的,所以时间复杂度是nlogn
- 可以对sort进行重载小于号,全局模式进行排序,也是可以的
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
//所谓前向星的租用就是记录好从某个起点开始的边的个数
//因为所有的都是在数组中,所以需要记录好这条边在数组中的位置是哪里,以及这条边的长度,
const int maxn = 10000;
struct Edge
{
int u, v, w;
friend bool operator<(const Edge &E1, const Edge &E2);
} e[maxn];
bool operator<(const Edge &E1, const Edge &E2)
{
if (E1.u != E2.u)
return E1.u < E2.u;
else if (E1.v != E2.v)
return E1.v < E2.v;
else
return E1.w < E2.w;
}
int head[maxn], len[maxn];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
cin >> e[i].u >> e[i].v >> e[i].w;
len[e[i].u]++;
}
sort(e + 1, e + 1 + m);
memset(head, -1, sizeof(head));
//最开始的起点一定是编号为1的
head[e[1].u] = 1;
for (int j = 2; j <= m; j++)
if (e[j].u != e[j - 1].u)
head[e[j].u] = j;
//通过head输出所有对应的边
for(int i = 1;i <= n;i++)
{
cout << "head: " << head[i] << " len = " << len[i] << endl;
for(int j = head[i]; j != -1 && j <= head[i]-1+ len[i];j++)
cout << e[j].u << " " << e[j].v << " " << e[j].w << endl;
}
return 0;
}
之前的实现代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
////#define LOCAL
const int MAXN = 10000;
struct Edge
{
int from, to, w;
//直接写排序规则 起点 , 终点, 权值
bool operator < (const Edge e) const
{
if(from != e.from)
return from < e.from;
else if(to != e.to)
return to < e.to;
else
return w < e.w;
}
}
edge[MAXN];
using namespace std;
int len[MAXN] ,head[MAXN];
//前向星:对边进行排序,按照起点、终点、权值排好顺序 ,同时记录下以某个点为起点的所有边在数组
//的起始位置和数组长度
int main()
{
int n,m;
cin >> n >> m;
//开始输入边的数据,起点,终点,权值
for(int i = 1;i <= m;i++)
{
cin >> edge[i].from >> edge[i].to >> edge[i].w;
len[edge[i].from]++;
}
//构建head[i]数组 和len[i]数组
//head[i] :以i为起点 在排序好的边集数组中的位置
sort(edge+1,edge+m+1);
memset(head,-1,sizeof(head)); // 所有的数值设置为-1,表示没有以该条边为起点的
head[edge[1].from] = 1;
for(int i = 2;i <= m;i++)
{
if(edge[i].from != edge[i-1].from)//当两个起点不一样的时候开始排
head[edge[i].from] = i;
}
//构建好之后 开始输出每个数据
for(int i = 1;i <= n;i++)
{
printf("head %d = %d , len = %d\n",i,head[i],len[i]);
for(int j = head[i] ; head[i] != -1 && j < head[i]+len[i];j++)
{
printf("%d %d %d\n",edge[j].from, edge[j].to, edge[j].w);
}
}
return 0;
}
1859

被折叠的 条评论
为什么被折叠?



