链式前向星 学习笔记

板子题-图的dfs

题目描述

一个有n个节点的连通图,这些节点以编号:1,2,n (1n,e1000000)进行编号,现给出节点间的连接关系。请以节点1为起点,按dfs的顺序遍历并输出该图。

输入

第一行为两整数,ne,表示n个顶点,e条边
以下e行每行两个数,表示两个节点是联通的

输出

只有一行,为节点的dfs顺序

样例输入

5 6
1 2
1 3
1 4
2 4
3 5
4 5

样例输出

1 2 4 5 3

算法理解

这道题目,其实可以使用简单的邻接矩阵,但是,对于一个稀疏图来说,这会很浪费空间。就比如说这样的一张图:

1
2
3
...
1000

如果使用邻接矩阵来储存的话,会非常浪费空间的,如果n的值很大的话保证MLE甚至RE那么,我们该怎么办呢?

算法实现

链式前向星就可以解决。这是利用链表进行操作的,没有学过链表的同学可以点这里

邻接表的构造

上图(样例):

1
2
3
4
5

用邻接表来表示就是这样的:

起始点 到达点1 到达点2 到达点3
1 2 3 4
2 4 / /
3 5 / /
4 5 / /
5 / / /
我们把这5条链表都存放在一个数组当中。用一个head数组,其中headi表示第i个点头指针。然后就是数据域to和指针域nex就可以了,当nexi的值为1的时候,就证明这个点是链表的结尾。

插入

还是来一张图(下标从1开始):
在这里插入图片描述
很简单,先把这个点的后驱设置为头,然后把头设置为这个点即可。
代码实现:

void add(int x,int y){
to[k]=y;
nex[k]=head[x];
head[x]=k;
k++;
return;
}

使用

插入之后,那么怎么用呢?是个问题。
不说了,看代码:

void dfs(int cur){
if(see[cur]) return;//如果去过就fanhui
printf("%d ",cur);//输出路径
see[cur]=1;//标记
for(int i=head[cur];i!=-1;i=nex[i]){//像链表一样查找
dfs(to[i]);//继续递归
}
return;
}

广告:如果你没有学过DFS,可以看这里

题目解析

其实,如果把这两段代码以及主函数写好,是过不了样例的,因为最重要的是按照字典序排列,所以,还要加上一段sort,当然因为地址不连续,就要自己打了,发现自己sort用太多连冒泡都不会打了
一切都在代码里::

void my_sort(int x){//x代表从x开始的点的排序
int f,a[maxn],nn;//f储存当前节点
f=head[x];//a储存地址
nn=0;//nn储存这个点的出度
memset(a,0,sizeof(a));//清零
while(f!=-1){//记录每一个数的地址
nn++;//统计数量
a[nn]=f;
f=nex[f]
}
if(nn==1||nn==0) return;//如果只有一个或者没有直接返回
int tmp,flag=1;
for(register int i=1;i<=nn;i++){//冒泡排序
flag=1;
for(register int j=nn-1;j>=i;j--)
if(to[a[j]]>=to[a[j+1]]){
flag=0;
tmp=to[a[j]];
to[a[j]]=to[a[j+1]];
to[a[j+1]]=tmp;
}
if(flag) return;//小优化
}
return;
}

然后是你们~最~爱的AC代码::

#include<cstdio>
#include<cstring>
#define maxn 100039
using namespace std;
int to[maxn],nex[maxn],head[maxn],k;
int n,m,i,x,y;
void add(int x,int y){
to[k]=y;
nex[k]=head[x];
head[x]=k;
k++;
return;
}
void my_sort(int x){
int f,a[maxn],nn;
f=head[x];
nn=0;
memset(a,0,sizeof(a));
while(f!=-1){
nn++;
a[nn]=f;
f=nex[f];
}
if(nn==1||nn==0) return;
int tmp,flag=1;
for(register int i=1;i<=nn;i++){
flag=1;
for(register int j=nn-1;j>=i;j--)
if(to[a[j]]>=to[a[j+1]]){
flag=0;
tmp=to[a[j]];
to[a[j]]=to[a[j+1]];
to[a[j+1]]=tmp;
}
if(flag) return;
}
return;
}
int see[maxn];
void dfs(int cur){
if(see[cur]) return;
printf("%d ",cur);
see[cur]=1;
for(int i=head[cur];i!=-1;i=nex[i]){
dfs(to[i]);
}
return;
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
add(x,y);
}
for(i=1;i<=n;i++)
my_sort(i);
dfs(1);
return 0;
}

注:这是我的成果(62行的代码),请勿抄袭!
广告:我的博客 欢迎各位大佬们前来指教本蒟蒻

posted @   jiangtaizhe001  阅读(91)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示