当前位置: 首页 > news >正文

数据结构 —— 图的遍历

数据结构 —— 图的遍历

  • BFS(广度遍历)
  • 一道美团题
  • DFS(深度遍历)

我们今天来看图的遍历,其实都是之前在二叉树中提过的方法,深度和广度遍历

在这之前,我们先用一个邻接矩阵来表示一个图:

#pragma once
#include<iostream>
#include<vector>
#include<map>
using namespace std;//图的模板化
namespace matrix
{template<class V, class W, W MAX_W, bool Direction = false>class Graph{public:Graph(const V* vertex, size_t n){//开辟空间_vertex.reserve(n);for (int i = 0; i < n; i++){_vertex.push_back(vertex[i]);_index[vertex[i]] = i;}//初始化矩阵_matrix.resize(n);for (auto& e : _matrix){e.resize(n, MAX_W);}}//寻找图中的点size_t FindSrci(const V& vertex){auto ret = _index.find(vertex);if (ret != _index.end()){return ret->second;}else{throw invalid_argument("不存在的顶点");return -1;}}void _AddEdge(size_t srci, size_t desi, W w){_matrix[srci][desi] = w;if (Direction == false){_matrix[desi][srci] = w;}}//加边void AddEdge(const V& srci, const V& desi, W w){size_t srcIndex = FindSrci(srci);size_t desIndex = FindSrci(desi);_AddEdge(srcIndex, desIndex, w);}void Print(){//打印标题行cout << "      ";for (int i = 0; i < _vertex.size(); i++){cout << _vertex[i] << " ";}cout << endl;//打印矩阵for (int i = 0; i < _vertex.size(); i++){cout << _vertex[i] << " ";for (int j = 0; j < _matrix[i].size(); j++){if (_matrix[i][j] != MAX_W){printf("%5d", _matrix[i][j]);}else{printf("%5c", '#');}}cout << endl;}}private://存放顶点vector<V> _vertex;//映射关系map<V, size_t> _index;//矩阵,图的表示vector<vector<W>> _matrix;};void TestGraph(){Graph<char, int, INT_MAX, true> g("0123", 4);g.AddEdge('0', '1', 1);g.AddEdge('0', '3', 4);g.AddEdge('1', '3', 2);g.AddEdge('1', '2', 9);g.AddEdge('2', '3', 8);g.AddEdge('2', '1', 5);g.AddEdge('2', '0', 3);g.AddEdge('3', '2', 6);g.Print();}void TestGraph2(){string a[] = {"海皇","高斯","小傲","小潮","胖迪","小杨","皖皖"};Graph<string, int,INT_MAX, false> g1(a, sizeof(a)/sizeof(a[0]));g1.AddEdge("小潮", "小傲", 30);g1.AddEdge("小潮", "高斯", 83);g1.AddEdge("小潮", "海皇", 34);g1.AddEdge("胖迪", "海皇", 78);g1.AddEdge("胖迪", "小傲", 76);g1.AddEdge("小杨", "皖皖", 54);g1.AddEdge("小杨", "高斯", 48);g1.Print();}
}

在这里插入图片描述在这里插入图片描述

BFS(广度遍历)

广度优先遍历和之前二叉树的广度优先遍历一样,我们需要队列来辅助
在这里插入图片描述我们逻辑上是这张图,但是我们实际遍历的时候,我们遍历的是一个矩阵(二维数组)
在这里插入图片描述因为这个图是联通图,我们从任意一个顶点出发都可以遍历完所有顶点,假设我们从小潮开始:
在这里插入图片描述我们仿照二叉树那里的思路,把相连的节点入队列,把小傲,高斯,海皇入队列:
在这里插入图片描述在矩阵上的表现就是把小潮这一行,不为#的数值的结点入队列
在这里插入图片描述好,现在有一个问题,假设我现在遍历到了海皇,海皇和小潮相连,按照上面的规则,我们应该把小潮入队列,但是我们一开始就是从小潮开始的,就会造成重复访问,这该则么办呢?

所以在图这里,我们要引入一个数组,标记我们已经访问过的结点,标记过的结点在之后的访问过程中不再入队

在这里插入图片描述
我们来实现一下:

	void BFS(const V& vertex){int vertexIndex = FindSrci(vertex);//队列和标记数组int n = _vertex.size();queue<size_t> q;vector<bool> visited(n, false);//先入最先访问节点q.push(vertexIndex);//标记visited[vertexIndex] = true;while (!q.empty()){//出队size_t front = q.front();q.pop();cout << _vertex[front] << " ";//遍历该行for (int i = 0; i < _vertex.size(); i++){if (_matrix[front][i] != MAX_W){if (visited[i] == false){q.push(i);visited[i] = true;}}}cout << endl;}}

一道美团题

在这里插入图片描述读了题之后,这里让我们计算几度好友,其实我们在BFS已经按照一度二度的顺序打印了,但是我们没有区分,我们区分一下就可以了

void BFS(const V& vertex)
{// 获取目标顶点的索引int vertexIndex = FindSrci(vertex);// 初始化队列和标记数组int n = _vertex.size();queue<size_t> q; // 创建一个队列用于存储待访问的顶点vector<bool> visited(n, false); // 创建一个布尔数组,用于标记顶点是否已被访问// 将起始顶点添加到队列中,并标记为已访问q.push(vertexIndex);visited[vertexIndex] = true;int levelSize = 1; // 初始化当前层级的顶点数量,初始时只有起始顶点int degree = 0; // 初始化度数(即好友的层次)// 当队列非空时,继续广度优先搜索while (!q.empty()){// 输出当前度数的好友cout << "[" << degree << "]" << "度好友 ";// 对当前层级的所有顶点进行处理for (int j = 0; j < levelSize; j++){// 从队列中取出一个顶点size_t front = q.front();q.pop();// 输出当前顶点的信息cout << _vertex[front] << " ";// 遍历与当前顶点相邻的所有顶点for (int i = 0; i < _vertex.size(); i++){// 如果存在一条边连接当前顶点和下一个顶点if (_matrix[front][i] != MAX_W){// 如果下一个顶点未被访问过if (!visited[i]){// 将下一个顶点添加到队列中,以便后续访问q.push(i);// 标记下一个顶点为已访问visited[i] = true;}}}}// 更新下一层级的顶点数量levelSize = q.size();// 换行输出,准备进入下一度数的好友输出cout << endl;// 增加度数计数器degree++;}// 最终换行,使输出更清晰cout << endl;
}

在这里插入图片描述

DFS(深度遍历)

深度遍历是一条道走到黑:
在这里插入图片描述

// 深度优先搜索的私有辅助函数
void _DFS(size_t vertexIndex, vector<bool>& visited)
{// 如果当前顶点尚未访问过if (!visited[vertexIndex]){// 输出当前顶点的值cout << _vertex[vertexIndex] << endl;// 将当前顶点标记为已访问visited[vertexIndex] = true;// 遍历所有顶点for (size_t i = 0; i < _vertex.size(); i++){// 如果当前顶点和遍历到的下一个顶点之间存在边,// 表示为权重不是最大可能权重(MAX_W),// 则对下一个顶点进行深度优先搜索if (_matrix[vertexIndex][i] != MAX_W)_DFS(i, visited);}}
}// 公开的深度优先搜索函数,从给定的顶点开始
void DFS(const V& vertex)
{// 查找给定顶点在顶点列表中的索引size_t vertexIndex = FindSrci(vertex);// 初始化一个布尔向量来跟踪每个顶点是否已被访问vector<bool> visited(_vertex.size(), false);// 调用私有辅助函数进行深度优先搜索_DFS(vertexIndex, visited);
}

在这里插入图片描述
(注:本人是小潮院长粉丝,该文章中举的例子不代表真实好友关系,无意挑拨小潮院长内部成员关系,如有冒犯,请不要打我…)

在这里插入图片描述

相关文章:

  • 【12321骚扰电话举报受理中心-短信验证安全分析报告】
  • 昇思学习打卡-3-张量Tensor
  • HarmonyOS ArkUi ArkWeb加载不出网页问题踩坑
  • 狄克斯特拉算法
  • 基于SpringBoot的CSGO赛事管理系统
  • Vue2-Vue Router前端路由实现思路
  • 事务底层与高可用原理
  • linux中 nginx+tomcat 部署方式 tomcat挂掉设置自动启动
  • Elasticsearch架构基本原理
  • C++时区转换
  • 51单片机第15步_串口多机通讯使用CRC8校验
  • 信创产业政策,信创测试方面
  • 44 mysql batch insert 的实现
  • JavaScript懒加载图像
  • Vue移动端地图App:van-uploader导致的卡顿问题
  • 3.7、@ResponseBody 和 @RestController
  • 77. Combinations
  • ES6 学习笔记(一)let,const和解构赋值
  • Git的一些常用操作
  • java概述
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • SSH 免密登录
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • VUE es6技巧写法(持续更新中~~~)
  • Vue--数据传输
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • 从零开始学习部署
  • 第2章 网络文档
  • 开源SQL-on-Hadoop系统一览
  • 容器化应用: 在阿里云搭建多节点 Openshift 集群
  • 三栏布局总结
  • 温故知新之javascript面向对象
  • 延迟脚本的方式
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • ​水经微图Web1.5.0版即将上线
  • "无招胜有招"nbsp;史上最全的互…
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • ${ }的特别功能
  • (52)只出现一次的数字III
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (阿里巴巴 dubbo,有数据库,可执行 )dubbo zookeeper spring demo
  • (七)Knockout 创建自定义绑定
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (一)SpringBoot3---尚硅谷总结
  • (转)Windows2003安全设置/维护
  • (转)创业的注意事项
  • .Net CF下精确的计时器
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .NET Core引入性能分析引导优化
  • .NET Windows:删除文件夹后立即判断,有可能依然存在
  • .NET 某和OA办公系统全局绕过漏洞分析
  • .net操作Excel出错解决
  • .Net高阶异常处理第二篇~~ dump进阶之MiniDumpWriter
  • .NET设计模式(7):创建型模式专题总结(Creational Pattern)