算法学习(5)-图的遍历

目录

什么是深度和广度优先

图的深度优先遍历-城市地图

图的广度优先遍历-最少转机


什么是深度和广度优先

         使用深度优先搜索来遍历这个图的过程具体是:

  1. 首先从一个未走到过的顶点作为起始顶点, 比如以1号顶点作为起点。
  2. 沿1号顶点的边去尝试访问其它未走到过的顶点, 首先发现2 号顶点还没有走到过, 于是来到了2 号顶点。
  3. 再以2 号顶点作为出发点继续尝试访问其它未走到过的顶点, 这样又来到了4号顶点。
  4. 再以4 号顶点作为出发点继续尝试访问其它未走到过的顶点。
  5. 但是, 此时沿4号顶点的边, 已经不能访问到其它未走到过的顶点了, 所以要返回到2号顶点。
  6. 返回到2号顶点后, 发现沿2 号顶点的边也不能再访问到其它未走到过的顶点。因此还需要继续返回到1号顶点。
  7. 再继续沿1号顶点的边看看还能否访问到其它未走到过的顶点。
  8. 此时又会来到3号顶点, 再以3号顶点作为出发点继续访问其它未走到过的顶点, 千是又来到5号顶点。
  9. 到此, 所有顶点都走到过了, 遍历结束。

        深度优先遍历的主要思想就是:首先以一个未被访问过的顶点作为起始顶点,沿当前顶点的边走到未访问过的顶点;没有未访问过的顶点时, 则回到上一个顶点, 继续试探访问别的顶点, 直到所有的顶点都被访问过。

        显然, 深度优先遍历是沿着图的某一条分支遍历直到末端, 然后回溯, 再沿着另一条进行同样的遍历, 直到所有的顶点都被访问过为止。那这一过程如何用代码来实现呢?在讲代码实现之前我们先来解决如何存储一个图的问题。最常用的方法是使用一个二维数组e来存储, 如下。

 

        上图二维数组中第i行第j列表示的就是顶点 i 到顶点 j 是否有边。1表示有边, ∞表示
没有边, 这里我们将自己到自己(即i等于j)设为0。我们将这种存储图的方法称为图的邻
接矩阵存储法。
        注意观察会发现这个二维数组是沿主对角线对称的, 因为上面这个图是无向图。所谓无向阳指的就是图的边没有方向, 例如边1-5表示, 1号顶点可以到5号顶点, 5号顶点也可以到1号顶点。
        接下来要解决的问题就是如何用深度优先搜索来实现遍历了。 

void dfs(int cur) { // cur是当前所在的顶点编号printf("%d. ", cur);sum++; // 每访问一个顶点s就加1if (sum == n) return; // 所有的顶点都已经访问过则直接退出for (i = 1; i <= n; i++) { // 从1号顶点到n号顶点依次尝试,看哪些顶点与当前顶点cur有边相连// 判断当前顶点cur到顶点i是否有边,并判断顶点i是否已访问过if (e[cur][i] == 1 && book[i] == 0) {// 标记顶点i已经访问过book[i] = 1;// 从顶点i再出发继续遍历dfs(i);}}return;
}

        在上面的代码中变揽cur存储的是当前正在遍历的顶点, 二维数组e存储的就是图的边(邻接矩阵), 数组book用来记录哪些顶点已经访问过, 变揽sum用来记录已经访问过多少个顶点, 变证n存储的是图的顶点的总个数。完整代码如下。

#include <stdio.h>int book[101], sum, n, e[101][101];void dfs(int cur) { // cur是当前所在的顶点编号int i;printf("%d ", cur);sum++; // 每访问一个顶点,sum就加1if (sum == n) return; // 所有的顶点都已经访问过则直接退出for (i = 1; i <= n; i++) { // 从1号顶点到n号顶点依次尝试,看哪些顶点与当前顶点cur有边相连// 判断当前顶点cur到顶点i是否有边, 并判断顶点i是否已访问过if (e[cur][i] == 1 && book[i] == 0) {// 标记顶点i已经访问过book[i] = 1;// 从顶点i再出发继续遍历dfs(i);}}return;
}int main() {int i, j, m, a, b;scanf("%d %d", &n, &m);// 初始化二维矩阵for (i = 1; i <= n; i++) {for (j = 1; j <= n; j++) {if (i == j)e[i][j] = 0;elsee[i][j] = 99999999; // 我们这里假设999999999为正无穷}}// 读入顶点之间的边for (i = 1; i <= m; i++) {scanf("%d %d", &a, &b);e[a][b] = 1;e[b][a] = 1; // 这里是无向图,所以需要将e[b][a]也赋为1}// 从1号城市出发book[1] = 1; // 标记1号顶点已访问dfs(1); // 从1号顶点开始遍历getchar();getchar();return 0;
}

        广度优先遍历的主要思想就是:首先以一个未被访问过的顶点作为起始顶点,访问其所有相邻的顶点, 然后对每个相邻的顶点,再访问它们相邻的未被访问过的顶点,直到所有顶点都被访问过, 遍历结束。

        代码实现如下:

#include <stdio.h>int main() {int i, j, n, m, a, b, cur;int book[101] = {0}; // 使用数组初始化语法将book数组初始化为全0int e[101][101];int que[10001], head = 0, tail = 0; // 将队列初始化为0scanf("%d %d", &n, &m);// 初始化二维矩阵for (i = 1; i <= n; i++) {for (j = 1; j <= n; j++) {if (i == j) {e[i][j] = 0;}else {e[i][j] = 99999999; // 假设999999999为正无穷}}}// 读入顶点之间的边for (i = 1; i <= m; i++) {scanf("%d %d", &a, &b);e[a][b] = 1;e[b][a] = 1; // 无向图,需要双向赋值}// 从1号顶点出发,将1号顶点加入队列que[tail] = 1;tail++;book[1] = 1; // 标记1号顶点已访问// 当队列不为空时循环while (head < tail) {cur = que[head]; // 当前正在访问的顶点编号// 从1~n依次尝试for (i = 1; i <= n; i++) {// 判断从顶点cur到顶点i是否有边,且顶点i是否已经访问过if (e[cur][i] == 1 && book[i] == 0) {// 如果从顶点cur到顶点i有边,并且顶点i没有被访问过,则将顶点i入队que[tail] = i;tail++;book[i] = 1; // 标记顶点i已访问}}// 如果tail大于n,则所有顶点都已经被访问过,退出循环if (tail > n) {break;}head++; // 顶点扩展结束后,head++,继续往下扩展}// 输出队列中的顶点编号for (i = 0; i < tail; i++) {printf("%d ", que[i]);}getchar();getchar();return 0;
}

图的深度优先遍历-城市地图

         我们可以创建一个5*5的邻接矩阵,如下图:

        用book数组记录哪些城市已经走过,用全局变量min来更新每次找到的路径的最小值,代码实现如下:

#include <stdio.h>
int min = 99999999, book[101], n, e[101][101]; // 我们这里假设999999999为正无穷// cur是当前所在的城市编号,dis是当前已经走过的路程
void dfs(int cur, int dis) {int j;// 如果当前走过的路程已经大于之前找到的最短路,则没有必要再往下尝试了,立即返回if (dis > min)return;if (cur == n)  // 判断是否到达了目标城市{if (dis < min) {min = dis;  // 更新最小值return;}}for (j = 1; j <= n; j++) { // 从1号城市到n号城市依次尝试// 判断当前城市cur到城市j是否有路,并判断城市j是否在已走过的路径中if (e[cur][j] != 99999999 && book[j] == 0) {book[j] = 1;  // 标记城市j已经在路径中dfs(j, dis + e[cur][j]);  // 从城市j再出发,继续寻找目标城市book[j] = 0;  // 之前一步探索完毕之后,取消对城市j的标记}}
}int main() {int i, j, m, a, b, c;scanf("%d %d", &n, &m);// 初始化二维矩阵for (i = 1; i <= n; i++)for (j = 1; j <= n; j++)if (i == j)e[i][j] = 0;elsee[i][j] = 99999999;// 读入城市之间的道路for (i = 1; i <= m; i++) {scanf("%d %d %d", &a, &b, &c);e[a][b] = c;}// 从1号城市出发book[1] = 1;  // 标记1号城市已经在路径中dfs(1, 0);  // 1表示当前所在的城市编号,0表示当前已经走过的路程printf("%d\n", min);  // 打印1号城市到目标城市的最短路径getchar();getchar();return 0;
}


图的广度优先遍历-最少转机

 

#include <stdio.h>struct note {int x;  // 城市编号int s;  // 转机次数
};int main() {struct note que[2501];// 初始化int e[51][51] = {0}, book[51] = {0};int head, tail;int i, j, n, m, a, b, cur, start, end, flag = 0;scanf("%d %d %d %d", &n, &m, &start, &end);// 初始化二维矩阵for (i = 1; i <= n; i++) {for (j = 1; j <= n; j++) {if (i == j)e[i][j] = 0;elsee[i][j] = 99999999;}}// 读入城市之间的航班for (i = 1; i <= m; i++) {scanf("%d %d", &a, &b);// 注:这里是无向图e[a][b] = 1;e[b][a] = 1;}// 队列初始化head = 1;tail = 1;// 从start号城市出发,将start号城市加入队列que[tail].x = start;que[tail].s = 0;tail++;book[start] = 1;  // 标记start号城市已在队列中// 当队列不为空的时候循环while (head < tail) {cur = que[head].x;  // 当前队列中首城市的编号for (j = 1; j <= n; j++) {  // 从1~n依次尝试// 从城市cur到城市j是否有航班并且判断城市j是否已经在队列中if (e[cur][j] != 99999999 && book[j] == 0) {// 如果从城市cur到城市j有航班并且城市j不在队列中,则将城市j入队que[tail].x = j;que[tail].s = que[head].s + 1;  // 转机次数+1tail++;// 标记城市j已经在队列中book[j] = 1;// 如果到达目标城市,停止扩展,任务结束,退出循环if (que[tail].x == end) {// 注意下面两句话的位置千万不要写颠倒了flag = 1;break;}}}if (flag == 1)break;head++;  // 注意这地方,千万不要忘记当一个点扩展结束后,head++才能继续扩展}// 打印队列中末尾最后一个(目标城市)的转机次数// 注意:tail是指向队列队尾(即最后一位)的下一个位置,所以这里要-1printf("%d\n", que[tail - 1].s);getchar();getchar();return 0;
}

         当然也可以使用深度优先搜索解决, 但是这里用广度优先搜索会更快。广度优先搜索更
加适用于所有边的权值相同的情况。

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

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

相关文章

【PyTorch与深度学习】2、PyTorch张量的运算API(上)

课程地址 最近做实验发现自己还是基础框架上掌握得不好&#xff0c;于是开始重学一遍PyTorch框架&#xff0c;这个是课程笔记&#xff0c;这个课还是讲的简略&#xff0c;我半小时的课听了一个半小时。 1. 张量 1.1 张量操作 &#xff08;1&#xff09;chunk&#xff1a;将一…

Java web应用性能分析之【sysbench基准测试】

Java web应用性能分析之【CPU飙高分析之MySQL】-CSDN博客 Java web应用性能分析之【Linux服务器性能监控分析概叙】-CSDN博客 Java web应用性能分析概叙-CSDN博客 Java web应用性能分析之【基准测试】-CSDN博客 上面基本科普了一下基准测试&#xff0c;这里我们将从sysbench…

【喜报】科大睿智为武汉博睿英特科技高质量通过CMMI3级评估咨询工作

武汉博睿英特科技有限公司是信息通信技术产品、建筑智慧工程服务提供商。其拥有专注于航空、政府、教育、金融等多行业领域的资深团队&#xff0c;及时掌握最新信息通信应用技术&#xff0c;深刻理解行业业务流程&#xff0c;擅于整合市场优质资源&#xff0c;积极保持与高校产…

苹果电脑如何轻松抹掉NTFS格式磁盘 如何将Mac系统下硬盘格式化为NTFS Mac硬盘格式化

在苹果电脑的操作系统下&#xff0c;对于磁盘格式的转换基本是每个电脑使用者都会进行的操作&#xff0c;一般是为了使磁盘更好地在电脑上存储文件。 NTFS&#xff08;New Technology File System&#xff09;是一种Windows系统常用的文件系统&#xff0c;而Mac电脑则默认使用…

java案例-服务端与客户端(传输对象)

需求 代码 SysUser 用户类Operation 操作类Client 客户端Server 服务端ServerReaderThread 服务端线程类 SysUser 用户类 需要实现Serializable 方便序列化&#xff0c;传输对象 public class SysUser implements Serializable {private String username;private String passwo…

小型架构实验模拟

一 实验需求 二 实验环境 22 机器&#xff1a; 做nginx 反向代理 做静态资源服务器 装 nginx keepalived filebeat 44机器&#xff1a; 做22 机器的备胎 装nginx keepalived 99机器&#xff1a;做mysql的主 装mysqld 装node 装filebeat 77机器&#xff1a;做mysq…

Git零基础

Git工作流程图 操作指令 分支 、 指令总结 远程仓库

ubuntu安装Anaconda安装及conda使用

一. 安装anaconda3详细教程 1、下载镜像 清华大学开源软件镜像站下载地址&#xff1a; https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 下拉到最低端选择Linux&#xff0c;选择最新版&#xff08;32/64位&#xff09;下载。这里我下载的是版本Anaconda3-4.3.30-Linux…

python应用-socket网络编程(1)

目录 1 先简单回顾下客户端和服务端通信的知识 2 服务端常用函数 3 客户端常用函数 4 服务端和客户端都用的函数 5 示例介绍客户端和服务端通信过程 6 建立服务端套接制 7 创建服务端函数socket.create_server() 8 创建客户端套接字 9 客户端连接函数socket.create_co…

Asp .Net Core 系列:国际化多语言配置

文章目录 概述术语 本地化器IStringLocalizer在服务类中使用本地化 IStringLocalizerFactoryIHtmlLocalizerIViewLocalizer 资源文件区域性回退 配置 CultureProvider内置的 RequestCultureProvider实现自定义 RequestCultureProvider使用 Json 资源文件 设计原理IStringLocali…

MATLAB语音信号分析与合成——MATLAB语音信号分析学习资料汇总(图书、代码和视频)

教科书&#xff1a;MATLAB语音信号分析与合成&#xff08;第2版&#xff09; 链接&#xff08;含配套源代码&#xff09;&#xff1a;https://pan.baidu.com/s/1pXMPD_9TRpJmubPGaRKANw?pwd32rf 提取码&#xff1a;32rf 基础入门视频&#xff1a; 视频链接&#xff1a; 清…

Eclipse C++ 无法debug 问题

环境&#xff1a; ubuntu20.04 Eclipse CDT&#xff08;x86_64) 工程&#xff0c;使用的是默认的CMake Project 现象&#xff1a; 1. 使用Eclipse&#xff0c; 加了断点后&#xff0c;debug 无法停在断点&#xff1b;step over 执行后是从main 直接执行到exit &#xff…

七彩虹(Colorful)隐星P16 2023款笔记本电脑原装出厂Win11系统镜像下载 带建Recovery一键还原功能

七彩虹原厂Windows预装OEM专用系统&#xff0c;恢复出厂开箱状态一模一样 适用型号&#xff1a;隐星P16 23 链接&#xff1a;https://pan.baidu.com/s/1Ig5MQMiC8k4VSuCOZRQHUw?pwdak5l 提取码&#xff1a;ak5l 原厂W11系统自带所有驱动、出厂时自带的主题与专用壁纸、系…

分类预测 | Matlab实现POA-BP鹈鹕算法优化BP神经网络多特征分类预测

分类预测 | Matlab实现POA-BP鹈鹕算法优化BP神经网络多特征分类预测 目录 分类预测 | Matlab实现POA-BP鹈鹕算法优化BP神经网络多特征分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.Matlab实现POA-BP鹈鹕算法优化BP神经网络多特征分类预测&#xff08;Matlab实…

31 OpenCV 距离变换和分水岭算法

文章目录 距离变换分水岭算法distanceTransform 距离变换watershed 分水岭算法示例 距离变换 分水岭算法 distanceTransform 距离变换 void cv::distanceTransform (InputArray src,OutputArray dst,int distanceType,int maskSize,int dstType CV_32F) src:输入图像&#xf…

Android 学习 鸿蒙HarmonyOS 4.0 第二天(项目结构认识)

项目结构认识 和 了解&#xff1a; 工程目录下的结构如下&#xff1a; 首先能看到有两个.开头的文件&#xff0c;分别是.hvigor 和 .idea。这两个文件夹都是与构建有关系的&#xff0c; 如果你开发过安卓app&#xff0c;构建完会生成一个apk安装包&#xff0c;鸿蒙则是生成hap…

maya blendshape

目录 shape编辑器 maya创建blendshape python 脚本 添加形变动画 查看顶点个数 shape编辑器 打开方式&#xff1a; 窗口-动画编辑器-形变编辑器 maya创建blendshape python 脚本 import maya.cmds as cmds# 创建基础网格 - 球体 baseMesh cmds.polySphere(name"bas…

一文讲解Android车载系统camera架构 - EVS

Android的camera开发中&#xff0c;使用最多的是camera2 以及现在Google主推的cameraX 架构&#xff0c;而这两个架构主要针对的是手机移动端上camera的流程。 而今天介绍的EVS(Exterior View System)架构是不同于camera2上的手机架构&#xff0c;针对Automotive的版本&#x…

ETL中双流合并和多流合并的区别

一、ETL工具 ETLCloud数据集成平台集实时数据集成和离线数据集成以及API发布为一体的数据集成平台。与其他开源数据集成工具相比&#xff0c;采用轻量化架构、具有更快的部署速度、更快的数据传输速度、更低的运维成本&#xff0c;同时支持多租户的团队协作能力&#xff0c;能…

opencv_17_翻转与旋转

一、图像翻转 1&#xff09;void flip_test(Mat& image); 2&#xff09;void ColorInvert::flip_test(Mat& image) { Mat dst; //flip(image, dst, 0); //上下翻转 flip(image, dst, 1); //左右翻转 // flip(image, dst, -1); //180度翻转 imsho…