深入理解链式前向星

原文链接

  首先我们了解一种数据结构,前向星,是以存边的方式存图的。我们把边集数组中的每一条边按照起点从小到大排序,如果起点相同就按照终点从小到大排序,并记录下以某个点为起点的所有边在数组中的起始位置和存储长度,那么前向星就构造好了.用len[i]来记录所有以i为起点的边在数组中的存储长度.用head[i]记录以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))。

如果采用链式前向星我们就能避免排序。

我们建立边结构体为:

struct Edge

{

int next;

int to;

int w;

};

其中edge[i].to表示第i条边的终点,edge[i].next表示与第i条边同起点的下一条边的存储位置,edge[i].w为边权值.

另外还有一个数组head[],它是用来表示以i为起点的第一条边存储的位置,实际上你会发现这里的第一条边存储的位置其实

在以i为起点的所有边的最后输入的那个编号.

head[]数组一般初始化为-1,对于加边的add函数是这样的:

1 void add(int u,int v,int w)
2 {
3     edge[cnt].w = w;
4     edge[cnt].to = v;
5     edge[cnt].next = head[u];
6     head[u] = cnt++;
7 }

初始化cnt = 0,这样,现在我们还是按照上面的图和输入来模拟一下:

edge[0].to = 2;     edge[0].next = -1;      head[1] = 0;

edge[1].to = 3;     edge[1].next = -1;      head[2] = 1;

edge[2].to = 4;     edge[2],next = -1;      head[3] = 2;

edge[3].to = 3;     edge[3].next = 0;       head[1] = 3;

edge[4].to = 1;     edge[4].next = -1;      head[4] = 4;

edge[5].to = 5;     edge[5].next = 3;       head[1] = 5;

edge[6].to = 5;     edge[6].next = 4;       head[4] = 6;

很明显,head[i]保存的是以i为起点的所有边中编号最大的那个,而把这个当作顶点i的第一条起始边的位置.

这样在遍历时是倒着遍历的,也就是说与输入顺序是相反的,不过这样不影响结果的正确性.

比如以上图为例,以节点1为起点的边有3条,它们的编号分别是0,3,5   而head[1] = 5

我们在遍历以u节点为起始位置的所有边的时候是这样的:

1 for(int i=head[u];~i;i=edge[i].next)

那么就是说先遍历编号为5的边,也就是head[1],然后就是edge[5].next,也就是编号3的边,然后继续edge[3].next,也

就是编号0的边,可以看出是逆序的.

原文地址:https://www.cnblogs.com/bianjunting/p/10699923.html

时间: 2024-11-07 05:33:21

深入理解链式前向星的相关文章

深度理解链式前向星——转载自ACdreamer

转载自ACdreamer [转载]深度理解链式前向星 我们首先来看一下什么是前向星. 前向星是一种特殊的边集数组,我们把边集数组中的每一条边按照起点从小到大排序,如果起点相同就按照终点从小到大排序, 并记录下以某个点为起点的所有边在数组中的起始位置和存储长度,那么前向星就构造好了. 用len[i]来记录所有以i为起点的边在数组中的存储长度. 用head[i]记录以i为[起点的]边集在数组中的第一个存储位置.            (???↑↑↑??蒟蒻表示这个好像是大佬的小失误,按自己的想法加了

深度理解链式前向星

转载自http://blog.csdn.net/acdreamers/article/details/16902023 我们首先来看一下什么是前向星.   前向星是一种特殊的边集数组,我们把边集数组中的每一条边按照起点从小到大排序,如果起点相同就按照终点从小到大排序, 并记录下以某个点为起点的所有边在数组中的起始位置和存储长度,那么前向星就构造好了.   用len[i]来记录所有以i为起点的边在数组中的存储长度. 用head[i]记录以i为边集在数组中的第一个存储位置.   那么对于下图:  

hdu2647 逆拓扑,链式前向星。

原文地址 题目分析 题意 老板发工资,但是要保证发的工资数满足每个人的期望,比如A期望工资大于B,只需比B多1元钱即可.老板发的最低工资为888元.输出老板最少发的工资总数,若是无法满足大家的期望,则输出-1. 分析 很明显这是一个拓扑问题,若存在环则无法满足大家的期望.若按常理,A>B,则可能会建立A指向B的有向边.此题不然,因为我们只知道最少的钱数是888,所以从小到大进行拓扑排序更为恰当.所以是建立B指向A的有向边.此之为逆拓扑排序.因为这样处理后排序的结果与原先拓扑排序的顺序相反. 以图

【前向星】链式前向星实现以及它的遍历

深度理解链式前向星 链式前向星的构成由一个结构体(包括目标点.边权值和下一个同起点的边)和head数组(用于存放某点的第一条出边) 必要的时候还可以添加一个统计入度的数组,因为进行BFS DFS的时候是依靠点的出度和出边的邻接关系来进行的.假如有多于一个点的入度为0,那么将只能遍历到其中一个点以及往后的内容. 对于链式前向星:链式前向星每添加一条边就会更新head数组,使得head数组存放的总是最新添加的某点的出边,此出边的next总指向head数组之前存放的出边的序号. 我们输入边的顺序为:

图论_链式前向星

参考自https://blog.csdn.net/ACdreamers/article/details/16902023(深度理解链式前向星-acdreams) 对于前向星,我的理解就是将边集按照起点顺序进行排序后存储(而并没有将终点也进行排序的必要).同时head[u]记录以u为起点的边集在数组中的第一个(读入时首次出现)存储位置. 前向星的优化:一开始读入时,先算出每个点出去的边有多少条,然后计算出排序后每个点出去的第一条边位置应在哪里,最后把全部边扫一遍放到排序后应在的位置就好了. --摘

UESTC30-最短路-Floyd最短路、spfa+链式前向星建图

最短路 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的T-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗? Input 输入包括多组数据. 每组数据第一行是两个整数NN ,MM (N≤100N≤100 ,M≤10000M≤1000

链式前向星

重要的事情说三遍 明天不学会链式前向星我绝食三天

图的存储结构:邻接矩阵(邻接表)&链式前向星

[概念]疏松图&稠密图: 疏松图指,点连接的边不多的图,反之(点连接的边多)则为稠密图. Tips:邻接矩阵与邻接表相比,疏松图多用邻接表,稠密图多用邻接矩阵. 邻接矩阵: 开一个二维数组graph[ ][ ]来记录图中点a与点b之间是否连通,初始化为0(或者-1之类的看情况):如果图中有可忽略的重边(如 只需重边中的最小边或最大边),则保存需要的那条边的边权,但如果有无法忽略的重边,就一定不要用邻接矩阵. int graph[MAXN][MAXN]; void graphInit() { me

HDU3342 Legal or Not【拓扑排序】【链式前向星】

Legal or Not Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4633    Accepted Submission(s): 2115 Problem Description ACM-DIY is a large QQ group where many excellent acmers get together. It is