链式前向星 学习笔记
板子题-图的dfs
题目描述
一个有n个节点的连通图,这些节点以编号: ()进行编号,现给出节点间的连接关系。请以节点1为起点,按dfs的顺序遍历并输出该图。
输入
第一行为两整数,和,表示个顶点,条边
以下行每行两个数,表示两个节点是联通的
输出
只有一行,为节点的dfs顺序
样例输入
5 6
1 2
1 3
1 4
2 4
3 5
4 5
样例输出
1 2 4 5 3
算法理解
这道题目,其实可以使用简单的邻接矩阵,但是,对于一个稀疏图来说,这会很浪费空间。就比如说这样的一张图:
如果使用邻接矩阵来储存的话,会非常浪费空间的,如果的值很大的话保证MLE甚至RE那么,我们该怎么办呢?
算法实现
链式前向星就可以解决。这是利用链表进行操作的,没有学过链表的同学可以点这里。
邻接表的构造
上图(样例):
用邻接表来表示就是这样的:
起始点 | 到达点1 | 到达点2 | 到达点3 |
---|---|---|---|
1 | 2 | 3 | 4 |
2 | 4 | / | / |
3 | 5 | / | / |
4 | 5 | / | / |
5 | / | / | / |
我们把这5条链表都存放在一个数组当中。用一个数组,其中表示第个点头指针。然后就是数据域和指针域就可以了,当的值为的时候,就证明这个点是链表的结尾。 |
插入
还是来一张图(下标从开始):
很简单,先把这个点的后驱设置为头,然后把头设置为这个点即可。
代码实现:
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行的代码),请勿抄袭!
广告:我的博客 欢迎各位大佬们前来指教本蒟蒻
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· 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工具