图遍历详解(C语言版)

图遍历详解(C语言版)图遍历详解 C 语言版 深度优先遍历 广度优先遍历 连通图或强连通图遍历 非连通图遍历


一、定义

        从给定图中任意指定的顶点(称为初始点)出发,按照某种搜索方法沿着图的边访问图中所有顶点,使每个顶点仅被访问一次,这个过程称为图的遍历。如果给定图是连通的无向图或者是强连通的有向图,则遍历过程一次就能完成,并可按访问的先后顺序得到由该图的所有顶点组成的一个序列。

二、方法

1、深度优先遍历

在这里插入图片描述
        该图以A为初始点,从左往右通过深度优先遍历可以得到序列:ABDHECFG ,当然如果采取从右往左通过深度优先遍历可以得到序列:ACGFBEHD,可见采用深度优先遍历得到的序列并不是唯一的,这与建图时的存储有关,假如采用邻接表来存储,当每个顶点的邻接顶点采用头插法插入,那么之后采用深度优先遍历进行遍历时就会得到序列ACGFBEHD,当每个顶点的邻接顶点采用尾插法插入,那么之后采用深度优先遍历进行遍历就得到序列ABDHECFG。
        下面来看看深度优先遍历的代码

//深度优先遍历: g:图 v:初始点 visited:标记数组 void DFS(GraphLnk *g, int v, bool visited[]) { 
     //访问顶点,获取值,打印 printf("%c-->",GetVertexValue(g,v)); visited[v] = true;//为访问过的顶点做上标记 int w = GetFirstNeighbor(g,GetVertexValue(g,v));//获取第一个邻接顶点 while(w != -1) { 
    //当邻接顶点未被访问 if(!visited[w]) { 
     DFS(g,w,visited);//以该顶点为起始顶点进行深度优先遍历 } /* 对第一个邻接顶点深度优先遍历完成,获取下一个邻接顶点的位置 (如果该顶点未被访问,那么下一轮将以该顶点为起始顶点进行深度优先遍历) */ w = GetNextNeighbor(g,GetVertexValue(g,v),GetVertexValue(g,w)); } } 

2、广度优先遍历

        广度优先遍历的过程是首先访问初始点v,接着访问顶点v的所有未被访问过的邻接点v1,v2,v3,…,vt,然后再按照v1,v2,v3,…,vt的次序访问每一个顶点的所有未被访问过的邻接点,依此类推,直到图中所有和初始点v有路径相通的顶点都被访问过为止。为了实现红色部分描述的先访问顶点的邻接顶点先访问,需要借用队列来实现。
        下面给出一个示例:

在这里插入图片描述
        该图以A为初始点,从左往右通过广度优先遍历可以得到序列:ABCDEFGH ,当然如果采取从右往左通过广度优先遍历可以得到序列:ACBGFEDH,可见采用广度优先遍历得到的序列也并不是唯一的,原因同深度优先遍历不唯一的原因,此处不再赘述。
        下面来看看广度优先遍历的代码

//广度优先遍历:g:图 v:初始点 visited:标记数组 void BFS(GraphLnk *g, int v, bool visited[]) { 
     printf("%c-->",GetVertexValue(g,v)); visited[v] = true; LinkQueue Q;//创建链队 InitQueue(&Q);//初始化 EnQueue(&Q,v);//将起始顶点入队 int w; while(!Empty(&Q))//当队内还有顶点 { 
     GetHead(&Q,&v);//获取存在在队头的顶点v DeQueue(&Q);//出队 //获取第一个邻接顶点 w = GetFirstNeighbor(g,GetVertexValue(g,v)); while(w != -1)//存在邻接顶点 { 
     if(!visited[w])//当该邻接顶点未被访问 { 
     //打印值 printf("%c-->",GetVertexValue(g,w)); visited[w] = true;//标记为已被访问 EnQueue(&Q,w);//将该顶点入队,为之后访问该顶点的邻接顶点做铺垫 } //获取顶点v的下一个邻接顶点(该邻接顶点的顺序在前面访问过邻接顶点w之后) w = GetNextNeighbor(g,GetVertexValue(g,v),GetVertexValue(g,w)); } } } 

三、实现

        有了上面的理论基础,下面将基于图的邻接表存储来实现图的遍历,如果大家对图的邻接表存储方式还不太理解,那么可以先阅读图之邻接表详解(C语言版)此篇文章之后,再接着往下阅读。

1、无向图或强连通有向图遍历

        如果给定图是连通的无向图或者是强连通的有向图,则遍历过程一次就能完成,并可按访问的先后顺序得到由该图的所有顶点组成的一个序列。

        深度优先遍历实现

//深度优先遍历:给出遍历的图g和起始顶点vertex void DFS(GraphLnk *g, T vertex) { 
     int n = g->NumVertices;//获取顶点个数 //根据顶点数建立辅助数组空间:用来标记哪些顶点已经访问过,哪些顶点没有访问 bool *visited = (bool*)malloc(sizeof(bool) * n); assert(visited != NULL); for(int i=0; i<n; ++i)//初始化标记数组 { 
     visited[i] = false; } //获取起始节点在邻接表中的位置 int v = GetVertexPos(g,vertex); DFS(g,v,visited);//遍历 free(visited);//释放辅助空间 } 

        广度优先遍历实现

//广度优先遍历:给出遍历的图g和起始顶点vertex void BFS(GraphLnk *g, T vertex) { 
     int n = g->NumVertices;//获取顶点个数 //根据顶点数建立辅助数组空间:用来标记哪些顶点已经访问过,哪些顶点没有访问 bool *visited = (bool*)malloc(sizeof(bool) * n); assert(visited != NULL); for(int i=0; i<n; ++i)//初始化标记数组 { 
     visited[i] = false; } //获取起始顶点在邻接表中的位置 int v = GetVertexPos(g,vertex); BFS(g,v,visited);//遍历  free(visited); } 

2、非连通图遍历

        如果给定图是非连通图,则只能访问到初始点所在分量中的所有顶点,其他连通分量中的顶点是不可能访问到的,为此需要从其他每个连通分量中选择初始点,分别进行遍历,这样才能够访问到图中的所有顶点。

        深度优先遍历实现

//非连通图的深度优先遍历方式 void NonUnicomDFS(GraphLnk *g) { 
     int n = g->NumVertices;//获取顶点个数 //根据顶点数建立辅助数组空间:用来标记哪些顶点已经访问过,哪些顶点没有访问 bool *visited = (bool*)malloc(sizeof(bool) * n); assert(visited != NULL); for(int i=0; i<n; ++i)//初始化标记数组 { 
     visited[i] = false; } for(i=0; i<n; ++i) //遍历非连通图的顶点 { 
     if(!visited[i])//以没有访问的顶点为起始顶点进行深度优先遍历 DFS(g,i,visited); } free(visited); } 

        广度优先遍历实现

//非连通图的广度优先遍历方式 void NonUnicomBFS(GraphLnk *g) { 
     int n = g->NumVertices;//获取顶点个数 //根据顶点数建立辅助数组空间:用来标记哪些顶点已经访问过,哪些顶点没有访问 bool *visited = (bool*)malloc(sizeof(bool) * n); assert(visited != NULL); for(int i=0; i<n; ++i)//初始化标记数组 { 
     visited[i] = false; } for(i=0; i<n; ++i) //遍历非连通图的顶点 { 
     if(!visited[i])//以没有访问的顶点为起始顶点进行广度优先遍历 BFS(g,i,visited); } free(visited); } 

结语

        对图遍历的介绍就到这里啦,希望这篇文章能给予你一些帮助,感谢各位人才的:点赞、收藏和评论,我们下次见。

附录

        测试代码:图遍历详解(C语言版)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/233628.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 第二代微服务

    第二代微服务

    2021年7月12日
    88
  • Microsoft Visio 2010密钥

    网上收集到的,备用参考在安装时可以使用以下密钥:GR24B-GC2XY-KRXRG-2TRJJ-4X7DCVWQ6G-37WBG-J7DJP-CY66Y-V278X2T8H8-JPW3D-CJGRK-3HTVF-VWD83HMCVF-BX8YB-JK46P-DP3KJ-9DRB222WT8-GGT7M-7MVKR-HF7Y4-MCWWDVX6BF-BHVDV-MHQ4R-KH9Q…

    2022年4月6日
    224
  • Python格式化字符串f-string概览

    Python格式化字符串f-string概览简介f-string,亦称为格式化字符串常量(formattedstringliterals),是Python3.6新引入的一种字符串格式化方法,该方法源于PEP498–LiteralStringInterpolation,主要目的是使格式化字符串的操作更加简便。f-string在形式上是以f或F修饰符引领的字符串(f’xxx’或F’xxx’),以大括号对{}标明…

    2022年6月10日
    67
  • 为什么百度查到的ip和ipconfig查到的不一样;详解公网Ip和私网ip;详解网络分类ABC;

    为什么百度查到的ip和ipconfig查到的不一样;详解公网Ip和私网ip;详解网络分类ABC; IP可以分为PublicIP和PrivateIP,出现这种规划的原因在于IPv4所能表示的IP太少而电脑太多以至于不够用,然而只有PublicIP才能直接连接上网络,所以对于那些公司,学校,政府机构等场所,就可以集中使用私有的IP进行管理,而大家可以共用一个IP去连接上公网,这样,就省下了许多宝贵的PublicIP。你有没有发现,你每次使用ipconfig查到的地址,要么就是172….

    2022年6月6日
    128
  • nextline函数_Java 中nextLine()方法没有执行直接跳过解决办法[通俗易懂]

    nextline函数_Java 中nextLine()方法没有执行直接跳过解决办法[通俗易懂]使用Java的Scanner类nextLne()方法从显示器输入数据时,nextInt()后面的nextLine()直接跳过没有执行;截图:第三个输入直接跳过通过上网的查找我终于发现了问题出在哪里:原来nextLine()函数获取的是一整行的内容其中也包括了(\n)也就是换行符而nextInt()函数获取的仅仅是一个值不包含(\n),那么nextInt()后面的nextLine()读取一行,就把(…

    2022年5月3日
    68
  • 【愚公系列】2022年02月 wireshark系列-数据抓包分析之DHCP协议

    【愚公系列】2022年02月 wireshark系列-数据抓包分析之DHCP协议实验步骤一获取DHCP数据包在windows平台上获取DHCP数据包在windows平台上,可以使用两种简单的方法实现,其原理一样。(1)在cmd上,使用ipconfig命令来获取。执行完上述命令后,将释放当前使用的地址信息。重新获取地址信息,执行命令如下执行完上面的命令后,将重新获取地址信息。在获取地址时,将会经过上面讲述的DHCP的4个阶段。这样,我们就能获取到DHCP数据包了。(2)通过禁用和启用网卡获取DHCP数据包在windows平台上,也可以通过禁用和启用网卡获取DHCP数

    2022年5月23日
    43

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号