图论入门--图的存储和遍历、DFS与BFS

无向图的对称性:g[i][j]=g[j][i],开两倍数组!!重要!

邻接矩阵的建立:

初始化正无穷大时若为int数组memset(g,0x7f,sizeof g)
若为0则memset(g,0,sizeof g)
若为很小数则为memset(g,0xaf,sizeof g)
double数组时memset(g,127,sizeof g)为很大数1.38*10306,memset(g,0,sizeof g)为0

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int g[200][200];//、、2倍数组,最多100,100 
int main(){
	int n,m;
	cin>>n>>m;//n个节点m个边 
	memset(g,0x7f,sizeof g);//、、初始化 
	for(int i=0;i<m;++i){
		int a,b,l;
		cin>>a>>b>>l;//点a到b(边ab)的权值 
		g[a][b]=l;
		g[b][a]=l;//、、无向图才有 ,有向图不要 
	}
	
	return 0;
}

邻接表(数组模拟链表):

比较复杂
首先结构体存的是边而不是点
而且是有向的
每条边有终点、当前边的起点节点出发的上一条边(next表示)、权值
全局一个edge结构体(存边)数组和一个记录边的编号的变量
以及一个head数组(第i号记录这个节点为起点编号最大的边即最后的边)
当要加边时 边的编号的变量++,然后edge数组记录下当前边的起点节点出发的上一个边,当前边的终点,当前边的权值
然后head数组更新当前边的起点节点的编号最大的边
由此可见,遍历一个节点相连的边,需要head【i】这条这个点出发的最后一个边,找这个边的next(即这个节点出发的上一条边)
然后再找现在这个边的next,直到这个边的next即上一条边为0就停止
但在c++中用next变量会ce,所以用nexts!!
edge数组的大小要看最大边数
head数组的大小要看最大节点数
但head这个变量是linux一个命令,所以会ce,用heads!!
这只是有向图的
无向图的要
addedge(u,v,l)
addedge(v,u,l)

代码:

#include<iostream>
#include<cstdio>
using namespace std;
struct edge{
	int nexts;//这条边的起点节点出发的上一条边 
	int to;//到达的点 
	int dis;//权值 
	
}edges[5010];
int num_edge=0,heads[100];
void addedge(int from,int to,int dis){
	edges[++num_edge].nexts =heads[from];
	edges[num_edge].to =to;
	edges[num_edge].dis =dis;
	heads[from]=num_edge;
}
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=0;i<m;++i){
		int u,v,l;
		cin>>u>>v>>l;
		addedge(u,v,l);
		addedge(v,u,l);//无向图才有 有向图不要
		 
	}
	for(int i=heads[1];i!=0;i=edges[i].nexts ){
		cout<<edges[i].dis <<" ";
	}

	cout<<endl;
	return 0;
}

邻接矩阵的dfs:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int g[200][200],visit[200];//visit判重,保证一个节点只走1次 
int n,m;
void dfs(int u){//邻接矩阵的dfs 
	if(visit[u])return ;
	visit[u]=1;
	cout<<u<<" ";
	for(int i=1;i<=n;++i){
		if(g[u][i]){
			dfs(i);
		}
	}
}
int main(){
	
	cin>>n>>m;
	memset(g,0,sizeof g);
	memset(visit,0,sizeof visit);
	for(int i=0;i<m;i++){
		int u,v;
		cin>>u>>v;
		g[u][v]=1;
		g[v][u]=1;
		
	}
	for(int i=1;i<=n;++i){//、、有的图不是连通的,为了保证所有节点都被访问所以要循环枚举节点 
		if(!visit[i]){//因为1次dfs后可能有的节点已经被访问过了 
			dfs(i);
		}
	}
	cout<<endl;
	return 0;
}

邻接表的dfs:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m;
struct edge{
	int nexts,to,dis;
}edges[5010];
int heads[101],visit[101],numedge=0;////visit判重,保证一个节点只走1次 
void addedge(int from,int to,int dis){
	edges[++numedge].nexts=heads[from];
	edges[numedge].to =to;
	edges[numedge].dis =dis;
	heads[from]=numedge;
}
void dfs(int u){//邻接表的dfs 
	if(visit[u])return;
	visit[u]=1;
	cout<<u<<" ";
	for(int i=heads[u];i!=0;i=edges[i].nexts ){
		dfs(edges[i].to );//注意这里,我们要的是所有点访问一次,所以必须dfs的是这条边到达的点!! 
	}
}
int main(){
	memset(visit,0,sizeof visit);
	cin>>n>>m;
	for(int i=0;i<m;++i){
		int u,v;
		cin>>u>>v;
		addedge(u,v,1);
		addedge(v,u,1);
		
	}
	for(int i=1;i <=n;++i){////、、有的图不是连通的,为了保证所有节点都被访问所以要循环枚举节点
		if(!visit[i]){ //因为1次dfs后可能有的节点已经被访问过了 
			dfs(i);
		}
	}
	cout<<endl;
	return 0;
}

无权图最短路的bfs:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int n,m;
struct edge{
	int nexts,dis,to;
} edges[5009];
int vis[101],heads[101],numedge=0,dis[101]; 
void addedge(int from,int to,int dis){
	edges[++numedge].nexts =heads[from];
	edges[numedge].dis =dis;
	edges[numedge].to =to;
	heads[from]=numedge;
} 
struct dian{
	int num,path;
};
queue<dian> q;
int main(){
	cin>>n>>m;
	memset(vis,0,sizeof vis);
	memset(dis,0,sizeof dis);
	for(int i=0;i<m;++i){
		int u,v;
		cin>>u>>v;
		addedge(u,v,1);
		addedge(v,u,1);
	}
	dian a;
	a.num =1;
	a.path =0;
	q.push(a);
	vis[1]=1;
	while(!q.empty()){//邻接表bfs 单源无权图最短路 
		dian b=q.front();
		q.pop();
		dis[b.num ]=b.path ;
		for(int i=heads[b.num ];i!=0;i=edges[i].nexts){
			if(!vis[edges[i].to ]){
				dian c;
				c.num =edges[i].to;
				c.path =b.path +1;
				vis[edges[i].to ]=1;//用点判重而不用边是因为一个点被扩展后不能再入队 
				q.push(c);
			}
		}
		
	}
	for(int i=1;i<=n;++i){
		cout<<dis[i]<<" ";
	}
	cout<<endl;
	return 0;
}
posted @ 2026-01-24 14:48  hicode002  阅读(2)  评论(0)    收藏  举报