栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【数据结构】图的遍历

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【数据结构】图的遍历

本文目录
  • 图的遍历
  • 遍历的分类
    • 深度优先遍历
      • 代码实现:
    • 广度优先遍历
      • 代码实现
  • 一笔画问题
    • 代码实现

图的遍历

从图中某一顶点出发,并系统地访问完图中的所有顶点,且都恰好访问一次的运算操作就被称作 图的遍历
图的遍历理解起来并不是很难,可以分开理解:“遍”意为全部,“历”意为经历、经过,合起来就是:全部顶点都经过一遍

注:为了避免重复访问了同一顶点,通常会使用一个标记数组visited来判断。visited[i]=0时代表还未访问,=1时代表已经访问过

遍历的分类

图的遍历方式分为两种:深度优先遍历与广度优先遍历,二者的时间复杂度都是O(n2)

深度优先遍历

运用:递归,回溯
方式:从起始点(假设是A)出发,并将点A标记好,然后再去访问与A相连,且未被访问过的顶点。一个中间的顶点(假设是B)在访问完B的所有邻接点后,再退回到B的上一个点(假设是C,即访问时由C到B),去访问C的另一个未被访问的邻接点,继续遍历。在选择邻接点遍历的先后时,一般准则是小序号优先

例如对于上面这个无向图进行深度优先遍历,起始点假定为1,程序的步骤为:
先由1 -> 2 -> 3的顺序访问,由于这时候1已经被标记,所以退回到2,再退回到1
从1开始再访问未被访问的点4,由于4没有邻接点,再退回到1
再从1访问未被访问的点5,再退回1
这时起始点的所有邻接点都被访问完毕,遍历结束。

代码实现:

(假设为邻接表存储)

void dfs(int u,int fa)//fa为上一个点
{
	if(visited[u])
		return;
	visited[u]=1;
	for(i=head[u];i;i=nxt[i])
	{
		if(to[i]=fa)//防止自环
			continue;
		dfs(to[i],u);	
	}
}
广度优先遍历

运用:队列
方式:与广搜BFS相似,所以广度优先遍历一张图,只要在BFS的基础上上稍作改动即可。

代码实现

(假设为邻接表储存)

void bfs(int index)
{
	memset(visited,0,sizeof(visited));
	int t,i;
	visited[index]=1;
	q.push(index);
	while(!q.empty())
	{
		t=q.front();
		q.pop();
		for(i=head[t];i;i=nxt[i])
		{
			if(!visited[to[i]])
			{	
				visited[to[i]]=1;
				q.push(to[i]);	
			}	
		}
	}
}
一笔画问题

如果有一个图存在一笔画,则这个一笔画的路径就是欧拉路,如果这条路径最后还回到了起点,那这个路就被称为欧拉回路

我们先定义奇点是这个点的度是奇数的点,偶点则是度为偶数个的点
那么存在以下两个定理:

  1. 欧拉路:图为连通图,且只有2个奇点
  2. 欧拉回路:图为连通图,且无向图中每个顶点都是偶点,有向图中每个顶点的出度等于入度
代码实现
#include
using namespace std;
stack s;
int head[1024];//顶点数
int nxt[2048],to[1024];//边数,如果是无向图边数*2
int visited[1024];//标记边有没有访问过 
int tot=1,cnt=0;
int ans[2048];
void add_edge(int u,int v)
{
	nxt[++tot]=head[u];
	to[tot]=v;
	head[u]=tot;
}
void euler(int index)
{
	int i,u;
	s.push(index);
	while(!s.empty())
	{
		u=s.top();//注意这里不弹栈,把当前这个点能访问的边都走一下,走到的点压在当前点之上 
		i=head[u];
		while(i&&visited[i])
			i=nxt[i];
		if(i)
		{
			s.push(to[i]);
			head[u]=nxt[i];//这里把访问过的边直接去掉,提高遍历效率 
			visited[i]=visited[i^1]=1;//如果是无向图,来回边都标记下 
		} 
		else
		{
			s.pop();
			ans[++cnt]=u;//这个数组看具体题目,用来保存欧拉遍历的结果,有时候可能是点有时候可能是边 
		} 
	}
}
int main()
{
	int i,n,m,u,v,w;
	scanf("%d %d",&n,&m); 
	for(i=0;i
		scanf("%d %d",&u,&v);
		add_edge(u,v);
		add_edge(v,u);
	} 
	euler(1);
	for(i=1;i<=cnt;i++)
		printf("%d ",ans[i]);
	return 0;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/935311.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号