数据结构 —— 图的遍历

news2025/1/13 13:36:00

数据结构 —— 图的遍历

  • 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);
}

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

在这里插入图片描述

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

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

相关文章

每日Attention学习8——Rectangular self-Calibration Attention

模块出处 [ECCV 24] [link] [code] Context-Guided Spatial Feature Reconstruction for Efficient Semantic Segmentation 模块名称 Rectangular self-Calibration Attention (RCA) 模块作用 空间注意力 模块结构 模块代码 import torch import torch.nn as nn import tor…

【2024版】Microsoft Azure 管理员培训课程招生简章(8月有开班)

课程介绍 本课程专为希望深入了解和精通Microsoft Azure管理的IT专业人员设计。在为期三天的培训中&#xff0c;学员将全面学习如何管理Azure订阅&#xff0c;保护标识&#xff0c;配置虚拟网络&#xff0c;以及实现存储解决方案和虚拟机。此外&#xff0c;课程还涵盖了实现We…

STL——list模拟实现

一、模拟实现源码 #pragma oncenamespace sjx {template <typename T>struct __list_node{__list_node<T>* _next;__list_node<T>* _prev;T _data;__list_node(const T& val T()) :_data(val), _next(nullptr), _prev(nullptr){}};template <typena…

HandlerMethodArgumentResolver :深入spring mvc参数解析机制

❃博主首页 &#xff1a; <码到三十五> ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a; 搬的每块砖&#xff0c;皆为峰峦之基&#xff1b;公众号搜索(码到三十…

【Pyhton】读取寄存器数据到MySQL数据库

目录 步骤 modsim32软件配置 Navicat for MySQL 代码实现 步骤 安装必要的库&#xff1a;确保安装了pymodbus和pymysql。 配置Modbus连接&#xff1a;设置Modbus从站的IP地址、端口&#xff08;对于TCP&#xff09;或串行通信参数&#xff08;对于RTU&#xff09;。 连接M…

昇思25天学习打卡营第10天 | 自然语言处理:RNN实现情感分类

1. RNN实现情感分类 1.2 概述 情感分类是自然语言处理中的经典任务&#xff0c;是典型的分类问题。本节使用MindSpore实现一个基于RNN网络的情感分类模型&#xff0c;实现如下的效果&#xff1a; 输入: This film is terrible 正确标签: Negative(负面) 预测标签: Negative输…

AlphaGo 背后的人工智能:机器学习和神经网络

文章目录 一、说明二、背景三、围棋游戏四、AlphaGo 算法五、神经网络六、AlphaGo 的未来七、人工智能的未来八、结论 一、说明 棋盘游戏围棋被视为人工智能最具挑战性的任务之一&#xff0c;因为它“复杂、基于模式且难以编程”。计算机程序 AlphaGo 战胜李世石成为人工智能和…

秋招突击——7/4——复习{}——新作{最长公共子序列、编辑距离}

文章目录 引言复习新作1143-最长公共子序列个人实现 参考实现编辑距离个人实现参考实现 贪心——买股票的最佳时机个人实现参考实现 贪心——55-跳跃游戏个人实现参考做法 总结 引言 昨天主要是面试&#xff0c;然后剩下的时间都是用来对面试中不会的东西进行查漏补缺&#xff…

xxl-job集成SpringBoot

安装xxl-job客户端一般有很多方式&#xff0c;我这里给大家提供两种安装方式&#xff0c;包含里面的各项配置等等。 前期需要准备好MySQL数据库。复制SQL到数据库里面。 # # XXL-JOB v2.4.2-SNAPSHOT # Copyright (c) 2015-present, xuxueli.CREATE database if NOT EXISTS x…

代码动态编译

背景 开发环境下新加代码、改代码时要重启后生效&#xff08;耗时间&#xff09;&#xff1b;需求:不用重启且支持springboot 、spring、MyBatis。 实现 下地地址&#xff1a;https://github.com/JetBrains/JetBrainsRuntime/releases 1.根据系统类型下载压缩包 2.解压后配…

手动将dingtalk-sdk-java jar包打入maven本地仓库

有时候,中央镜像库不一定有自己需要的jar包,这时候我们就需要用到该方法,将jar打入maven本地仓库,然后项目中,正常使用maven的引入规则。 mvn install:install-file -Dmaven.repo.local=D:\software\maven\apache-maven-3.6.3-bin\apache-maven-3.6.3\repo -DgroupId=ding…

生态共建 | 华宇TAS应用中间件与新华三服务器完成兼容互认证

近日&#xff0c;华宇TAS应用中间件完成与新华三技术有限公司的R4930系列和R4970 G7服务器的兼容适配&#xff0c;认证测试报告显示&#xff0c;双方产品兼容性良好&#xff0c;运行稳定、安全&#xff0c;可以满足用户对双方功能的要求。 新华三技术有限公司 新华三技术有限公…

《Winodws API每日一练》8.2 static控件

在 Windows 编程中&#xff0c;"Static" 控件是一种常见的用户界面元素&#xff0c;用于显示静态文本或图像&#xff0c;而无法进行用户交互。它通常用于显示标签、标题、说明文本或静态图像等信息。Static 控件是一种静态的、只读的显示元素&#xff0c;不接受用户的…

ConsiStory:无需训练的一致性文本到图像生成技术

随着大规模文本到图像&#xff08;T2I&#xff09;扩散模型的发展&#xff0c;用户可以更自由地通过文本指导图像生成过程。然而&#xff0c;要在不同的提示中保持同一主题的视觉一致性仍然是一个挑战。现有的方法通常需要对模型进行微调或预训练&#xff0c;以教授新词汇来描述…

信息安全驱动汽车行业快速向数字化转型

开发一款安全性良好的软件是困难的&#xff0c;它需要专业知识的积累以及对常见编程缺陷和规则的了解&#xff0c;例如检查输入范围、管理内存分配和回收、寻址字符串格式、避免悬空指针等等。通常情况下&#xff0c;编写安全代码与开发人员编写“流畅”代码的自然愿望形成了对…

滤波算法学习笔记

目录 引言 一、定义 二、分类 三、常见滤波算法 四、应用与优势 五、发展趋势 例程 1. 均值滤波&#xff08;Moving Average Filter&#xff09; 2. 中值滤波&#xff08;Median Filter&#xff09; 3. 高斯滤波&#xff08;Gaussian Filter&#xff09; 4.指数移动…

新技术 高效的碳捕捉技术设计

网盘 https://pan.baidu.com/s/1mUlEhbQ6LBHYdmfg-du9bw?pwdc7gk 一种用于高效捕集CO_Sub_2__Sub_的生物炭颗粒吸附剂及其制备方法和应用.pdf 基于双相离子溶液的高效碳捕集及节能再生装置.pdf 基于水合物法低温液化的高效碳捕集系统及其操作方法.pdf 碳捕集系统及方法.pdf 高…

Feign远程调用,请求头丢失情况

现象 解决方案 import feign.RequestInterceptor; import feign.RequestTemplate; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.context.request.RequestContextHolde…

一篇文章说清楚Filter(过滤器)、Interceptor(拦截器)和AOP(切面儿)

文章目录 前言一、Filter&#xff08;过滤器&#xff09;1.说明2.实现filterChain.doFilter() 3.order优先级4.解决跨域5.拦截返回错误信息JSON 二、Interceptor&#xff08;拦截器&#xff09;1.说明2.实现preHandlepostHandleafterCompletion 3.执行顺序图4.排除特定路径拦截…

C#/.NET/.NET Core编程技巧练习集

DotNet Exercises介绍 DotNetGuide专栏C#/.NET/.NET Core编程常用语法、算法、技巧、中间件、类库练习集&#xff0c;配套详细的文章教程讲解&#xff0c;助你快速掌握C#/.NET/.NET Core各种编程常用语法、算法、技巧、中间件、类库等等。 GitHub开源地址&#xff1a;https://…