图的邻接表存储方式.docx
《图的邻接表存储方式.docx》由会员分享,可在线阅读,更多相关《图的邻接表存储方式.docx(12页珍藏版)》请在冰豆网上搜索。
![图的邻接表存储方式.docx](https://file1.bdocx.com/fileroot1/2023-7/17/e2ad58a5-d03c-4eff-9f5d-c2922f7eaf04/e2ad58a5-d03c-4eff-9f5d-c2922f7eaf041.gif)
图的邻接表存储方式
图的邻接表存储方式——数组实现初探
焦作市外国语中学岳卫华
在图论中,图的存储结构最常用的就是就是邻接表和邻接矩阵。
一旦顶点的个数超过5000,邻接矩阵就会“爆掉”空间,那么就只能用邻接表来存储。
比如noip09的第三题,如果想过掉全部数据,就必须用邻接表来存储。
但是,在平时的教学中,发现用动态的链表来实现邻接表实现时,跟踪调试很困难,一些学生于是就觉得邻接表的存储方式很困难。
经过查找资料,发现,其实完全可以用静态的数组来实现邻接表。
本文就是对这种方式进行探讨。
我们知道,邻接表是用一个一维数组来存储顶点,并由顶点来扩展和其相邻的边。
具体表示如下图:
其相应的类型定义如下:
type
point=^node;
node=record
v:
integer;//另一个顶点
next:
point;//下一条边
end;
var
a:
array[1..maxv]ofpoint;
而用数组实现邻接表,则需要定义两个数组:
一个是顶点数组,一个是边集数组。
顶点编号
结点相临边的总数s
第一条邻接边next
此边的另一邻接点
边权值
下一个邻接边
对于上图来说,具体的邻接表就是:
由上图我们可以知道,和编号为1的顶点相邻的有3条边,第一条边在边集数组里的编号是5,而和编号为5同一个顶点的下条边的编号为3,再往下的边的编号是1,那么和顶点1相邻的3条边的编号分别就是5,3,1。
同理和顶点3相邻的3条边的编号分别是11,8,4。
如果理解数组表示邻接表的原理,那么实现就很容易了。
类型定义如下:
type
node=record//点集数组
s,next:
longint;//s为与第i个点相临的边有多少个,next为第一条边的编号为多少?
end;
edge=record//边集数组
y,v,next:
longint;//y为这条边的另一个顶点,v为权值,next为和第i个节点相临的另一条边,next为0则表示结束。
end;
var
a:
array[1..maxn]ofnode;
e:
array[1..maxm]ofedge;
见图的代码和动态邻接表类似:
readln(x1,y1,v1);
inc(m);e[m].y:
=y1;e[m].v:
=v1;e[m].next:
=a[x1].next;a[x1].next:
=m;
inc(a[x1].s);
inc(m);e[m].y:
=x1;e[m].v:
=v1;e[m].next:
=a[y1].next;a[y1].next:
=m;
inc(a[y1].s);
下面提供一道例题
邀请卡分发deliver.pas/c/cpp
【题目描述】
AMS公司决定在元旦之夜举办一个盛大展览会,将广泛邀请各方人士参加。
现在公司决定在该城市中的每个汽车站派一名员工向过往的行人分发邀请卡。
但是,该城市的交通系统非常特别,每条公共汽车线路都是单向的,且只包含两个车站,即起点站与终点站,汽车从起点到终点站后空车返回。
假设AMS公司位于1号车站,每天早上,这些员工从公司出发,分别到达各自的岗位进行邀请卡的分发,晚上再回到公司。
请你帮AMS公司编一个程序,计算出每天要为这些分发邀请卡的员工付的交通费最少为多少?
【输入文件】
输入文件的第一行包含两个整数P和Q(1<=P<=10000,0<=Q<=20000)。
P为车站总数(包含AMS公司),Q为公共汽车线路数目。
接下来有Q行,每行表示一条线路,包含三个数:
起点,终点和车费。
所有线路上的车费是正整数,且总和不超过1000000000。
并假设任何两个车站之间都可到达。
【输出文件】
输出文件仅有一行为公司花在分发邀请卡员工交通上的最少费用。
【样例输入】
Case1:
22
1213
2133
Case2:
46
1210
2160
1320
3410
245
4150
【样例输出】
Case1:
46
Case2:
210
【分析】此题是一道基本最短路径问题,但是如果想通过全部数据,10000个点,20000条边,必须用邻接表来实现。
下面给出此题目用dijkstra和spfa两种算法的实现。
programdelive_dijstrkalr;
const
inf='deliver.in';
ouf='deliver.out';
maxm=20000;
maxn=10000;
type
node=record
s,next:
longint;//s为与第i个点相临的边有多少个,next为第一条边的编号为多少?
end;
edge=record
y,v,next:
longint;//y为这条边的另一个顶点,v为权值,next为和第i个节点相临的另一条边,next为0则表示结束。
end;
var
i,j,k,m,n,x1,y1,w1,ans:
longint;
a,a1:
array[1..maxn]ofnode;
e,e1:
array[1..maxm]ofedge;
d,d1:
array[1..maxn]oflongint;
proceduredij;
var
i,j,k,min,jj,kk:
longint;
f:
array[1..maxn]ofboolean;
begin
fillchar(d,sizeof(d),$7f);
fillchar(f,sizeof(f),false);
j:
=a[1].next;
fori:
=1toa[1].sdo
begin
k:
=e[j].y;
d[k]:
=e[j].v;
j:
=e[j].next;
end;
//用邻接表来找和第1个点相临的点,并给d数组赋初值。
。
。
。
f[1]:
=true;d[1]:
=0;
fori:
=2tondo
begin
min:
=maxlongint;k:
=0;
forj:
=1tondo
if(notf[j])and(d[j]begin
min:
=d[j];k:
=j;
end;
ifk=0thenexit;
f[k]:
=true;
jj:
=a[k].next;
forj:
=1toa[k].sdo
begin
kk:
=e[jj].y;
if(notf[kk])and(d[k]+e[jj].vd[kk]:
=d[k]+e[jj].v;
jj:
=e[jj].next;
end;//邻接表的使用,要好好注意。
。
。
end;
end;
begin
assign(input,inf);reset(input);
assign(output,ouf);rewrite(output);
fillchar(a,sizeof(a),0);
fillchar(e,sizeof(e),0);
fillchar(a1,sizeof(a1),0);
fillchar(e1,sizeof(e1),0);
readln(n,m);
fori:
=1tomdo
begin
readln(x1,y1,w1);
e[i].y:
=y1;e[i].v:
=w1;
e[i].next:
=a[x1].next;a[x1].next:
=i;
inc(a[x1].s);
e1[i].y:
=x1;e1[i].v:
=w1;
e1[i].next:
=a1[y1].next;a1[y1].next:
=i;
inc(a1[y1].s);
end;
dij;
d1:
=d;
a:
=a1;e:
=e1;
dij;
ans:
=0;
fori:
=2tondo
ans:
=ans+d[i]+d1[i];
writeln(ans);
close(input);close(output);
end.
programdeliver;
const
inf='deliver.in';
ouf='deliver.out';
maxm=20000;
maxn=10000;
type
node=record
s,next:
longint;//s为与第i个点相临的边有多少个,next为第一条边的编号为多少?
end;
edge=record
y,v,next:
longint;//y为这条边的另一个顶点,v为权值,next为和第i个节点相临的另一条边,next为0则表示结束。
end;
var
i,j,k,m,n,x1,y1,w1,ans:
longint;
a,a1:
array[1..maxn]ofnode;
e,e1:
array[1..maxm]ofedge;
d,d1:
array[1..maxn]oflongint;
q:
array[1..100000]oflongint;
procedurespfa;//spfa是基于边的松弛操作的最短路径求法。
基本原理就是
var
i,j,k,now,min,t,w:
longint;
f:
array[1..maxn]ofboolean;
begin
fillchar(d,sizeof(d),$7f);
fillchar(f,sizeof(f),false);
fillchar(q,sizeof(q),0);
d[1]:
=0;
t:
=1;f[1]:
=true;
w:
=1;
q[t]:
=1;
repeat
k:
=q[t];
j:
=a[k].next;
fori:
=1toa[k].sdo
begin
now:
=e[j].y;
ifd[now]>d[k]+e[j].vthen
begin
d[now]:
=d[k]+e[j].v;
ifnotf[now]then
begin
inc(w);
q[w]:
=now;
f[now]:
=true;
end;
end;
j:
=e[j].next;
end;
f[k]:
=false;
inc(t);
untilt>w;
end;
begin
assign(input,inf);reset(input);
assign(output,ouf);rewrite(output);
fillchar(a,sizeof(a),0);
fillchar(e,sizeof(e),0);
fillchar(a1,sizeof(a1),0);
fillchar(e1,sizeof(e1),0);
readln(n,m);
fori:
=1tomdo
begin
readln(x1,y1,w1);
e[i].y:
=y1;e[i].v:
=w1;
e[i].next:
=a[x1].next;a[x1].next:
=i;
inc(a[x1].s);
e1[i].y:
=x1;e1[i].v:
=w1;
e1[i].next:
=a1[y1].next;a1[y1].next:
=i;
inc(a1[y1].s);
end;
spfa;
d1:
=d;
a:
=a1;e:
=e1;
spfa;
ans:
=0;
fori:
=2tondo
ans:
=ans+d[i]+d1[i];
writeln(ans);
close(input);close(output);
end.