今天我们学习了一个新知识——链表。
说起链表,我们首先来讲讲有向图和无向图:
1→ 3 →2
有向图也叫单向图,图中的1~3箭头意思是:从1可以到3,从3却不可以到1;其他的也是如此,链表也就是这样的单向图;
1—3—2
无向图也叫双向图,此图中,1和3连起来,就表示1可以到3,3也可以到1。虽然链表是单向图,但是两个单向图不就是一个双向图吗?所以我们做两个单向链表就是一个双向链表啦!
但是这只是我们自己画的一个图,在程序里面如何表示与储存呢?我就是用数组来储存的。
首先我们定义两个数组:普通数组head与结构体数组edge,edge里有t和next两个变量。Head用来记录每一个边最后一个到的边的编号,便于等下调用,edge则是用来记录每一条边的下一条边的编号与下一条边的位置,那代码如下:
void gouj(int k,int j)
{
cur++; //增加一条边
edge[cur].t=j;//存储 到哪条边
edge[cur].next=head[k];//上一个到哪条边
head[k]=cur;//更新边
}ps:所有数组初始值为-1;
具体如下:
假设要构建一个链表,分别是:
1 3 2 4 12 3 4
那么构建完后:
Edge数组
1 2 3 4 |
3 -1 4 -1 2 1 4 -1 |
Head数组
0 1 2 3 4 5
-1 | 3 | 2 | 4 | -1 | -1 |
第一次处理1 3这一条边时,由1到3,那么3为这条边的目标,存储在edge[1].t中,然后把head[1]存储到edge[1].next中(head就是这条边的起始地的上一个目标地,也就是上一个到哪条边 ),再把head[1]更新一下,就完成了一个链表的维护。
但是在查询链表时,要用到深度搜索(DFS)。
有一道链表的例题:
Smoj.nhedu.net题库的1528:奶牛的野餐
程序如下:
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;
int cur=-1,a,b,c,ans;
inthead[100000],kaishi[100000];
intzhuangtai[100000],farm[100000];
struct nhgp
{
int t,next;
}luo[100000];
void gouj(int k,int j)
{
cur++;
luo[cur].t=j;
luo[cur].next=head[k];
head[k]=cur;
}
void dfs(int kaishi1)
{
zhuangtai[kaishi1]=1;
farm[kaishi1]++;
int tmp=head[kaishi1];
while (tmp!=-1)
{
if(zhuangtai[luo[tmp].t]==0) dfs(luo[tmp].t);
tmp=luo[tmp].next;
}
zhuangtai[kaishi1]=2;
}
int main()
{
cin >>a>>b>>c;
for (int i=1;i<=a;i++)
cin >>kaishi[i];
memset(head,-1,sizeof(head));
for (int i=1,lukai,lujie;i<=c;i++)
{
cin>>lukai>>lujie;
gouj(lukai,lujie);
}
//检查图
/* for (int i=1;i<=c;i++)
cout <<head[i]<<" ";
cout << endl;
for (int i=0;i<=cur;i++)
cout <<luo[i].t<<" "<<luo[i].next<<endl;*/
for (int i=1;i<=a;i++)
{
memset(zhuangtai,0,sizeof(zhuangtai));
dfs(kaishi[i]);
}
for (int i=1;i<=b;i++)
if (farm[i]==a) ans++;
cout << ans;
return 0;
}