22图的遍历

图的遍历

 

图的遍历:搜索属于图的基本运算。树的先序遍历和按层遍历的推广。图的遍历也称搜索,主要有:

先深搜索(depth-first search)——深度优先搜索——dfs搜索

先广搜索(breadth-first search)——广度优先搜索——bfs搜索

 

遍历目的——完成图运算(求子图或路径):生成树,连通分量,无向图的双连通分量,有向图的强连通分量,有向图顶点的拓扑排序,判断有向图是否有回路,求解迷宫问题。

搜索应用:找出图的生成树、图的连通分量等。

 

1.先深搜索:

按一定的规律沿着图中的边访问每个顶点恰一次的运算称为对图的遍历(和二叉树遍历相仿)。

其实就是利用递归的思想。比如先访问A结点,而A结点与B相连,就访问B结点,若B与D相连,就接着访问D结点。。。。。。

 

先深搜索算法

(1)原始描述形式

步骤1)将图G中所有顶点作“未访问过”标记。

步骤2)任选某个未访问过的顶点v作搜索起点。

步骤3)访问v。

步骤4)选择v的每一个未访问过的邻接点w作起点,递归的搜索图G。

步骤5)若所有顶点均已访问过,则搜索结束;否则,转步骤2。

 

描述形式:

分成主控函数和递归的搜索函数

主控函数

步骤1)将图中每个顶点置未访问标记;

步骤2)检查每个顶点v,如果v未访问过,则dfs(v);递归的搜索函数dfs(v)

步骤3)访问v,并对v作“已访问”标记;

步骤4)检查v的每个邻接点w,如果w未访问过,则调用dfs(w);

步骤5)返回上一次调用点;

 

示例:

 

 

 

对无向图搜索的特点:

1)若连通,搜索路线构成先深生成树。

2)引起递归的边:树边(tree edge)和回边,或余边(back edge)将E划分成树边集T和回边集B  。

 

3)若步骤2和4中,如有多个顶点可选,可任选其一搜索路线不唯一,生成树不唯一。

4)若不连通图,产生先深生成森林。

5)不同的子生成树之间不可能有回边相连。

6)祖先的先深号必小于子孙的先深号,对子孙的搜索先终止,而对祖先的搜索后终止。

 

对有向图搜索的特点:

1)若强连通,可得到先深生成树。

2)非强连通,也不一定不能到先深生成树。

3)可将边集E划分成:树边T、回边B、向前边F和交叉边C 。

注意以下几个术语:

树边:引起递归调用的边。

回边:由子孙射向祖先的边。

 

向前边F(forward edges):由祖先射向子孙的边。

交叉边C(cross edges):无祖孙关系顶点之间的边。

4)先访问的顶点(先深号小)在上、在左,后访问的顶点在下、在右交叉边:由右射向左,而不会由左射向右。

5)树边和向前边:小号射向大号。

回边和交叉边:大号射向小号。

 

 

 

 

先深搜索的实现:

由主控函数和递归搜索函数dfs两部分共同完成

图的存储形式:邻接表。

顶点结点含有访问否标志域mark。

未访问点,mark值为0;已访问点,mark值为1。

主控函数的功能:

1.对顶点作未访问标记(即初始化)

2.检查是否存在未访问过的顶点

3.选择一个未访问过的顶点作为搜索起点

4.通过搜索起点调用递归的搜索函数dfs

 

搜索函数dfs(v)的功能:

1.置顶点v已访问标记,使其mark域为1

2.沿v的邻接表检查其各邻接点是否访问过

3.对未访问过的邻接点w,递归调用dfs(w)

4.当v的邻接表“走”完后,对v的搜索终止,退回到dfs(v)的调用点

 

主控函数

void main_1( )

     { int v;

      for (v=0;v<n;v++) L[v].mark=0;  //置未访问标记

      for (v=0;v<n;v++)   //检查各顶点是否访问过  

 

     if(L[v].mark= =0) //如果v未访问过

            dfs(v);  //选v作搜索起点,调用搜索函数

      …………  //  其他处理操作

}

 

搜索函数

void  dfs (int v)   //递归的搜索函数,v是顶点编号

   { Eptr  p;  int w;

     visit(v);  //  访问v

     L[v].mark=1; // 作访问标记 

     p=L[v].firstedge;  //p指向v的邻接表首结点

     while (p!=NULL)  //检查v的所有邻接点

     { w=p->adjacent;  //w是v的邻接点

       if (!L[w].mark)dfs(w);  //若w未访问过,递归调用dfs

       p=p->next;  //递归返回后,再查看v的下一个邻接点

         }

    }

 

 

先深搜索的应用:

对无向图的先深搜索,可以

1.判断是否连通

2.找出连通分量、双连通分量

3.找出生成树或生成林

对有向图的先深搜索,可以

1.判断图中是否存在回路

2.找出强连通分量

3.对顶点进行柘朴排序

 

 

求无向图的连通分量算法(这里只给出修改后的主控函数)

  void  dfsmain() 

    {   int v,k=0;

    for(v=0;v<n;v++)L[v].mark=0;

    for(v=0;v<n;v++)

    if(L[v].mark==0)

        {   k++;

            printf("第 %d  个连通分量:\n {",k);

            dfs(v);

            printf(" }\n");

       }

     } 

 

 

求无向图的先深生成树(林)算法(这里只给出修改说明)

主控函数不变

将搜索函数中的:

    if(!L[w].mark)dfs(w);

改为 :

   if (!L[w].mark)

       {  将(v,w)加进树边集; L[w].father=v; dfs(w); }

 

判断有向图是否存在回路原理:

执行dfs(v) 期间,区分:T、B、F、C

<v,w>是T,v是w父,w未访问过,dfs(v)未终止

<v,w>是F,v是w祖,dfs(w)已终止

<v,w>是C,v在w之右,dfs(w)已终止

<v,w>是B,w是v祖,w已访问过,dfs(w)未终止

 

结论:如果w已访问过,但dfs(w)尚未终止,

           则<v,w>必是回边

 

该标记mark的作用:

L[v].mark=0,表示v尚未访问过

L[v].mark=1,表示v已经访问过,但dfs(v)尚未终止

L[v].mark=2,表示v已经访问过,且dfs(v)已经终止

在进入dfs(v)之前,程序置L[v].mark=0

    在进入dfs(v)之后,程序置L[v].mark=1

dfs(v)结束处,置L[v].mark=2

 

判断有向图是否存在回路算法:

主控函数

void  dfsmain( )

  { int v;

     cycle=0;          //cycle是整体量

   for(v=0;v<n;v++)L[v].mark=0;

     for(v=0;v<n;v++)

       if(L[v].mark==0)dfs(v);

   if(cycle) printf("图中有回路\n");

     else  printf("图中没有回路\n");

  }

 

void  dfs (int v)   //递归的搜索函数,v是顶点编号

   { Eptr  p;  int w;

    visit(v);  //  访问v

    L[v].mark=1; // 作访问标记 

    p=L[v].firstedge;  //p指向v的邻接表首结点

    while (p!=NULL)  //检查v的所有邻接点

   { w=p->adjacent;  //w是v的邻接点

    if(L[w].mark==0)

dfs(w);

      elseif(L[w].mark==1)

cycle=1;

          //dfs(w)尚未终止,置有回路标记

    p=p->next;

    }

  L[v].mark=2;            //置dfs(v)终止标记

}

 

 

2.先广搜索

         优先选择广度,比如A与C、D、E、D,访问A结点后,依次访问C、D、E、D,不会继续递归访问与C相连接的结点。

 

是二叉树按层遍历的推广,算法描述:

步骤1)将图中所有顶点作“未访问过”标记。

步骤2)任选图中一个尚未访问过的顶点v作搜索起点。

步骤3)访问v。

步骤4)相继地访问与v相邻而尚未访问的所有顶点

  w1,w2……,并依次访问与这些顶点相邻而尚未访问过的所有顶点。

    反复如此,直到找不到这样的顶点。

步骤5)若图中尚有未访问过的顶点,则转步骤2;否则,搜索结束。

 

示例

 

 

 

 

 

先广搜索的实现:

图存储形式:邻接表

用一个队存放等待访问的顶点。

顶点结点含有进队否标志域mark。

未进队,mark值为0;已进过队,mark值为1。

注意点:使用队结构记录搜索路线(存放着等待访问的顶点)

 

 

 

 

图的先广搜索算法:

 

void  bfs( )

   { Eptr  p;     int  u,v,w,first,last,q[n]; 

1.   first=last=0;  //队列初始化

2.   for(u=0;u<n;u++) L[u].mark=0;  //初始化

3.   for(u=0;u<n;u++) //找未进过队的顶点

4.     if(!L[u].mark)  //若u未进队

5.      {  q[last++]=u;  //u进队

6.         L[u].mark=1;  //置u进队标记

7.         while(first!=last) //当队列不空时循环

8.           { v=q[first++];  //v出队

9.        visit(v);  //访问v

10.        p=L[v].firstedge; //检查v的邻接点

11.        while(p!=NULL)

12.          { w=p->adjacent;  // w是v的邻接点

13.             if (!L[w].mark)  //若w未进过队

14.                { q[last++]=w; L[w].mark=1; } w进队

15.               p=p->next; //找v的下一个邻接点

                } // 与句12对应

            } // 与句8对应,到队空

        } // 与句5对应,以u为起点的搜索结束

   }

 

两种搜索算法对照:

1.先深搜索算法比先广搜索算法结构好。

2.先深搜索可写成递归形式,而先广搜索无法写成递归形式

3.先深搜索更常用

 

转载于:https://www.cnblogs.com/gd-luojialin/p/8509515.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/414622.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cannot resolve symbol 'R',Failed to resolve: constraint-layout

1、当在github上下载demo项目在Android studio启动时&#xff0c;提示Cannot resolve symbol R。虽然提示错误&#xff0c;但是运行项目并没有问题 原因是gradle版本高于本地Android studio的gradle版本 把 classpath com.android.tools.build:gradle:3.3.1 改为 classpat…

Android Log工具类,Toast工具类,获取当前方法名称

Log新晋工具方法 public class LgqLog {private static boolean ifShowtrue;private static int sCurrentLogLevel Log.DEBUG;private static String sPrefix null;IntDef({ Log.VERBOSE, Log.DEBUG, Log.INFO, Log.WARN, Log.ERROR })Retention(RetentionPolicy.SOURCE)publ…

前端学习(2739):重读vue电商网站49之第三方库使用CDN

通过 externals 加载外部 CDN 资源 默认情况下&#xff0c;通过 import 语法导入的第三方依赖包&#xff0c;最终会被打包合并到同一个文件中&#xff0c;从而导致打包成功后&#xff0c;单文件体积过大的问题。 例如上述 chunk-vendors.js 体积很大&#xff0c;原因是全部 im…

Mysql--重点1

知识预览 sql语句规范数据类型数据库操作数据表操作表记录操作查询表记录(select)多表查询完整性约束回到顶部sql语句规范 sql是Structured Query Language(结构化查询语言)的缩写。SQL是专为数据库而建立的操作命令集&#xff0c;是一种功能齐全的数据库语言。 在使用它时&…

6、jeecg 笔记之 自定义excel 模板导出(一)

6、jeecg 笔记之 自定义excel 模板导出&#xff08;一&#xff09; 1、前言 jeecg 中已经自带 excel 的导出导出功能&#xff0c;其所使用的是 easypoi&#xff0c;尽管所导出的 excel 能满足大部分需求&#xff0c; 但总是有需要用到自定义 excel 导出模板&#xff0c;下文所…

Android Lambda 表达式使用实例,-

1、Lambda表达式理解 Lambda 表达式&#xff0c;也可称为闭包&#xff0c;它是推动 Java 8 发布的最重要新特性。 Lambda 允许把函数作为一个方法的参数&#xff08;函数作为参数传递进方法中&#xff09;。 使用Lambda 表达式可以使代码变的更加简洁紧凑。 2、Lambda表达式…

前端学习(2740):重读vue电商网站50之Element-UI 组件按需加载

通过 CDN 优化 ElementUI 的打包 虽然在开发阶段&#xff0c;我们启用了 element-ui 组件的按需加载&#xff0c;尽可能的减少了打包的体积&#xff0c;但是那些被按需加载的组件&#xff0c;还是占用了较大的文件体积。此时&#xff0c;我们可以将 element-ui 中的组件&#…

8、jeecg 笔记之 自定义word 模板导出(一)

8、jeecg 笔记之 自定义word 模板导出&#xff08;一&#xff09; 1、前言 jeecg 中已经自带 word 的导出导出功能&#xff0c;其所使用的也是 easypoi&#xff0c;尽管所导出的 word 能满足大部分需求&#xff0c; 但总是有需要用到自定义 word导出模板&#xff0c;下文所用到…

Android 全屏抽屉fragment,NavigationView

1、首先是右→左进入动画 、slide_left.xml <?xml version"1.0" encoding"utf-8"?> <set xmlns:android"http://schemas.android.com/apk/res/android"><translateandroid:duration"800"android:fromXDelta"20…

Eclipse 创建第一个 springboot 应用

Eclipse 创建第一个 springboot 应用 1、前言 一直想把笔记整理出来&#xff0c;分享一下 springboot 的搭建&#xff1b; 因为私下 idea 用的比较多&#xff0c;使用比较方便&#xff0c;但恰逢小伙伴问起 eclipse 怎么搭建的问题&#xff0c; 顾整理以记之。 2、springboot …

Can't process attribute android:fillColor=@color/gray,添加vector属性报错解决方法

Android studio添加vector属性文件报错 vector属性文件 <vector xmlns:android"http://schemas.android.com/apk/res/android"android:width"24dp"android:height"24dp"android:viewportHeight"49.94"android:viewportWidth"4…

前端学习(2742):重读vue电商网站52之路由懒加载

当打包构建项目时&#xff0c;JavaScript 包会变得非常大&#xff0c;影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块&#xff0c;然后当路由被访问的时候才加载对应组件&#xff0c;这样就更加高效了。 具体需要 3 步&#xff1a; 安装 babel/plugin-synt…

Android Service与IntentService区别

相同点&#xff1a; 1、首先Service与IntentService都是Android的基本组件service 2、使用时都是一样需要创建&#xff0c;配置&#xff1b;和调用启动方式都是一样的 不同点&#xff1a; 1、IntentService是继承自Service的service 类&#xff0c;创建了自己的特有方法onH…

前端学习(2743):重读vue电商网站53之项目上线

通过 node 创建 web 服务器。开启 gzip 配置。配置 https 服务。使用 pm2 管理应用。 通过 node 创建 web 服务器 创建 node 项目&#xff0c;并安装 express&#xff0c;通过 express 快速创建 web 服务器&#xff0c;将 vue 打包生成的 dist 文件夹&#xff0c;托管为静态资…

记录请求的耗时(拦截器、过滤器、aspect)

记录请求的耗时&#xff08;拦截器、过滤器、aspect&#xff09; 文章前言 记录控制器请求的耗时处理通常有三种实现方式&#xff0c;分别是&#xff1a;过滤器、拦截器、aspect&#xff1b;下文将逐一实现。 1、Filter 过滤器 1.1、方法说明 需要实现 Filter 类&#xff0c;主…

7、Flutter banner_view 轮播图的使用

7、Flutter banner_view 轮播图的使用 1、前言 实现轮播图&#xff0c;效果如下&#xff1a; 2、实现 将采用 banner_view 实现&#xff1a;资源库地址 2.1、yaml 引入依赖 在 pubspec.yaml 声明需要引用的库&#xff0c;执行命令 flutter packages get 进行拉取即可使用。 ba…

Android 人脸实名验证demo——腾讯人脸核身·云智慧眼

可以说比较容易实现&#xff1a;只需要获取BizToken&#xff0c;再起调腾讯SDK即可 1、首先登录腾讯云平台&#xff0c;申请权限&#xff0c;创建应用 腾讯云&#xff1a; https://cloud.tencent.com/ 2、配置应用信息及实名验证流程设置&#xff0c;下载SDK 不过&#xff0c;…

[JSOI 2015] 子集选取

4475: [Jsoi2015]子集选取 Time Limit: 1 Sec Memory Limit: 512 MBSubmit: 363 Solved: 255[Submit][Status][Discuss]Description Input 输入包含一行两个整数N和K&#xff0c;1<N,K<10^9 Output 一行一个整数&#xff0c;表示不同方案数目模1,000,000,007的值。 Sam…

工作242:关于第二个git仓库提交代码

其实第二个仓库 建立的时候直接取进行 push操作就可以完成 原理一样 可以直接对代码地址进行提交

工作243:name报错

name报错就是name的数值报错