【数据结构】基础:图的遍历实现(附C++源代码)

news2024/11/28 2:37:48

【数据结构】基础:图的遍历实现(附C++源代码)

摘要:将会在数据结构专题中开展关于图论的内容介绍,其中包括四部分,分别为图的概念与实现、图的遍历、图的最小生成树以及图的最短路径问题。本文将介绍图的遍历,分别为深度优先遍历和广度优先遍历,需要了解其实现实现与方法。


文章目录

  • 【数据结构】基础:图的遍历实现(附C++源代码)
    • 前言:图的实现方式
    • 一、广度优先遍历(BFS)
    • 二、深度优先遍历(DFS)

前言:图的实现方式

本文中图的实现方法为邻接矩阵法,以下是对其类的基本描述,若需查看更加具体的内容,可以参考博客图的概念与基本实现。其重点可以概括为:

  • Direction:表示是否为有向图
  • _vertexs:记录了对应检索下的顶点元素
  • _vIndexMap:记录了检索与顶点的对应关系
  • _matrix:表示邻接矩阵

具体代码如下:

template<class V, class W, bool Direction = false, W MAX_WEIGHT = INT_MAX>
    class Graph {
        typedef Graph<V, W, Direction, MAX_WEIGHT> Self;

        private:
        vector<V> _vertexs; // 顶点集合
        map<V, int> _vIndexMap; // 顶点检索
        vector<vector<W>> _matrix; // 邻接矩阵

        public:
        Graph() = default;
        Graph(const V* vertexs,size_t vertexSize) {
            _vertexs.reserve(vertexSize);
            for (size_t i = 0; i < vertexSize; i++) {
                _vertexs.push_back(vertexs[i]);
                _vIndexMap[vertexs[i]] = i;
            }

            // 格式化
            _matrix.resize(vertexSize);
            for (auto& e : _matrix) {
                e.resize(vertexSize, MAX_WEIGHT);
            }
            //for (size_t i = 0; i < _matrix.size(); i++) {
            //	_matrix[i][i] = 0;
            //}
        }

        size_t GetVertexIndex(const V& v) {
            auto ret = _vIndexMap.find(v);
            if (ret != _vIndexMap.end()) {
                return ret->second;
            }
            else {
                throw invalid_argument("不存在的顶点");
                return -1;
            }
        }

        void AddEdge(const V& src, const V& dest, const W& weight) {
            size_t srcIndex = GetVertexIndex(src);
            size_t destIndex = GetVertexIndex(dest);
            AddEdgeByIndex(srcIndex, destIndex, weight);
        }

        void AddEdgeByIndex(size_t srcIndex, size_t destIndex, const W& weight){
            _matrix[srcIndex][destIndex] = weight;
            if (Direction == false) {
                _matrix[destIndex][srcIndex] = weight;
            }
        }
    }

一、广度优先遍历(BFS)

概述:BFS,其英文全称是Breadth First Search,广度优先搜索是一种分层查找的过程。由于需要使用到分层查找,将会借助队列来帮助遍历。而为了避免重复访问的状况,借助一个容器,来记录访问状况。
在这里插入图片描述

算法实现

  • 将起点入队列,设置其为已访问的标识
  • 对于队列进行空判断,若不为空,访问队列头并出队列,设置已访问标识。再通过邻接矩阵访问其邻接节点,并入队列
  • 重复该过程直至队列为空

由于是广度优先遍历,可以对其添加层与层之间的关系,在此通过levelSizelevel实现,具体操作为在起点入队列后,对于levelSize设置为1,每次遍历了levelSize个节点后,对于levelSize进行更新为队列的元素个数,同时更新level

代码如下

void BFS(const V& src) {
    queue<int> q;
    vector<bool> visited(_vertexs.size(), false);

    int srcIndex = GetVertexIndex(src);
    q.push(srcIndex);
    visited[srcIndex] = true;
    int levelSize = 1;
    int level = 1;

    while (!q.empty()) {
        cout << "层高:" << levelSize << " 层数:" << level << endl;
        for (size_t i = 0; i < levelSize; i++) {
            int front = q.front();
            q.pop();
            cout << "[" <<front << "|" << _vertexs[front] << "] ";
            for (size_t j = 0; j < _vertexs.size(); j++) {
                if (visited[j] == false && _matrix[front][j] != MAX_WEIGHT 
                    && _matrix[front][j] != 0) {
                    q.push(j);
                    visited[j] = true;
                }
            }
        }
        cout << endl;
        levelSize = q.size();
        level++;
    }
}

测试用例

void TestBFSGraph() {
	Graph<char, int, 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);
	cout << endl;
	g.Print();

	cout << endl;
	g.BFS('3');
}

image-20230214145914900

二、深度优先遍历(DFS)

概述:DFS 全称是 Depth First Search,中文名是深度优先搜索,是一种用于遍历或搜索树或图的算法。所谓深度优先,就是说每次都尝试向更深的节点走。该算法实现可以转换为子问题求解,即使用递归完成该遍历方式。

在这里插入图片描述

算法实现

  • 为了避免重复访问的情况,在此设定一个visited容器记录结点是否被访问。
  • 算法的主题思路是使用递归完成,在递归访问一个结点后,通过邻接矩阵在此邻接点进行递归访问,直至访问完毕位置
  • 同时在每次访问时需要对visited容器中是否访问进行修改为真。
  • 为了防止出现多个森林的情况,在递归调用完起点后,进行对每个节点的再递归调用

代码如下

void DFS(const V& src) {
    size_t srcIndex = GetVertexIndex(src);
    vector<bool> visited(_vertexs.size(), false);
    _DFS(srcIndex, visited);
    cout << "nullptr" << endl;

    // 但不是连通图的时候
    for (size_t i = 0; i < _vertexs.size(); i++) {
        if (visited[i] == false) {
            _DFS(i, visited);
            cout << " nullptr" << endl;
        }
    }
}
void _DFS(int srcIndex, vector<bool>& visited) {
    visited[srcIndex] = true;
    cout << "[" << srcIndex << "|" << _vertexs[srcIndex] << "] -> ";
    for (size_t i = 0; i < _vertexs.size(); i++) {
        if (_matrix[srcIndex][i] != MAX_WEIGHT && _matrix[srcIndex][i] != 0 && visited[i] == false) {
            _DFS(i, visited);
        }
    }
}

测试用例

void TestDFSGraph() {
	Graph<char, int, 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);
	cout << endl;
	g.Print();

	cout << endl;
	g.DFS('3');
}

image-20230214151244926


补充:

  1. 代码将会放到:C++/C/数据结构代码链接 ,欢迎查看!
  2. 欢迎各位点赞、评论、收藏与关注,大家的支持是我更新的动力,我会继续不断地分享更多的知识!

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

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

相关文章

Python实现视频自动打码功能,避免看到羞羞的画面

前言 嗨呀嗨呀&#xff0c;最近重温了一档综艺节目 至于叫什么 这里就不细说了 老是看着看着就会看到一堆马赛克&#xff0c;由于太好奇了就找了一下原因&#xff0c;结果是因为某艺人塌房了…虽然但是 看综艺的时候满影响美观的 咳咳&#xff0c;这里我可不是来教你们如何解…

卡诺图化简

1.相关概念 最小项&#xff1a;函数的某个乘积项包含了函数的全部变量&#xff08;原变量或反变量的形式&#xff09;&#xff0c;且每个变量仅出现一次&#xff0c;则这个乘积项为该函数的一个标准积项。 最小项中的原变量记为1&#xff0c;反变量记为0&#xff0c;当变量顺序…

C++STL剖析(九)—— unordered_map和unordered_multimap的概念和使用

文章目录1. unordered_map的介绍和使用&#x1f351; unordered_map的构造&#x1f351; unordered_map的使用&#x1f345; insert&#x1f345; operator[ ]&#x1f345; find&#x1f345; erase&#x1f345; size&#x1f345; empty&#x1f345; clear&#x1f345; sw…

程序环境和预处理详解

文章目录一、程序环境1.1 - 翻译环境1.1.1 - 编译1.1.1.1 - 预编译&#xff08;预处理&#xff09;1.1.1.2 - 编译1.1.1.3 - 汇编1.1.2 - 链接1.2 - 执行环境二、预处理详解2.1 - 预定义符号2.2 - #define2.2.1 - #define 定义标识符2.2.1.1 - 语法2.2.1.2 - 建议2.2.2 - #defi…

AI极大地改变了知识创造与分发的逻辑

AI改变了&#xff5e;知识创造、分发的逻辑 细想一下这是恐怖的 已经传导出给教育的压力 趣讲大白话&#xff1a;AI机器人成了随身专家 *********** 1.以前靠秀才创造、分发知识 2.后来是教育体系为主 3.再后&#xff0c;互联网平台聚合和分发 4.将来可能大部分是机器人创造、分…

Xshell和Xftp的下载和在linux虚拟机中的使用

Xshell和Xftp的下载和在linux虚拟机中的使用一、Xshell和Xftp简介XshellXftp二、 Xshell和Xftp下载三、Xshell和Xftp安装Xshell安装Xftp安装四、 Xshell和Xftp使用找到linux虚拟机的ip地址Xshell的使用Xftp的使用一、Xshell和Xftp简介 Xshell Xshell 是一个强大的安全终端模拟…

对灵敏度分析技术进行建模(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

9、MyBatis框架——使用注解开发实现数据库增删改查操作、一级缓存、二级缓存、MyBatis实现分页

目录 一、使用注解开发实现数据库增删改查操作 1、搭建项目 2、使用注解开发操作数据库 二、一级缓存 1、一级缓存失效的情况 三、二级缓存 1、手动开启二级缓存cacheEnabled 2、二级缓存机制 四、MyBatis实现分页 1、配置环境 2、startPage()开启分页 3、PageInfo…

charles+夜神模拟器抓包

1.资料地址: 链接&#xff1a;https://pan.baidu.com/s/1w9qYfFPJcduN4If50ICccw 提取码&#xff1a;a7xa2.安装charles 和夜神模拟器并配置参考地址: https://www.beierblog.com/archives/%E4%BA%B2%E6%B5%8B%E5%AE%8C%E5%85%A8%E5%8F%AF%E8%A1%8Ccharles%E6%8A%93%E5%8C%85%E…

两道链表经典算法题---链表有无环(基础+进阶)

生活就像一盒巧克力&#xff0c;你永远不知道你会得到什么。——《阿甘正传》目前自己粗略的学完数据结构&#xff0c;正在开始刷算法题目。个人觉得算法是一个积累&#xff0c;循序渐进的的过程&#xff0c;需要不断加量&#xff0c;进而达到所谓的质。链表作为数据结构一个重…

全网详解MyBatis-Plus LambdaQueryWrapper的使用说明以及LambdaQueryWrapper和QueryWapper的区别

文章目录1. 文章引言2. 代码演示3. 分析LambdaQueryWrapper3.1 引入LambdaQueryWrapper的原因3.2 LambdaQueryWrapper和QueryWapper的区别4. 重要总结1. 文章引言 今天在公司写代码时&#xff0c;发现同事使用LambdaQueryWrapper来查询数据&#xff0c;而我一直习惯使用QueryW…

没对比没伤害,浙江男不买包包被女友拖拽,深圳男收三个女孩红包

又是一年一度的情人节&#xff0c;虽然这只是一个西方的节日&#xff0c;却被中国的商人们充分利用&#xff0c;也造成了不小的社会矛盾。在今年的情人节里&#xff0c;浙江就发生了一件奇葩的事情&#xff0c;一位女子因不满其男友 不给自己买两万元包包&#xff0c;就在商场里…

Onvif协议如何判断摄像机支持 —— 筑梦之路

有人就问什么是Onvif协议呢&#xff1f; 全称为&#xff1a;Open Network Video Interface Forum.缩写成Onvif。 翻译过来是&#xff1a;开放型网络视频接口论坛&#xff0c;目的是确保不同安防厂商的视频产品能够具有互通性&#xff0c;这样对整体安防行业才是良性发展。 现…

【C语言编译器】01程序-编译器-IDE

目录一、程序的几个基本概念二、什么是编译器三、集成开发环境3.1 IDE简介3.2 windows 下的C语言IDE一、程序的几个基本概念 计算机程序&#xff08;Computer Program&#xff09;&#xff1b;港、台译做电脑程式。计算机程序是一组计算机能识别和执行的指令&#xff0c;运行于…

5 款最好的免费 SSD 数据恢复软件

SSD&#xff08;固态硬盘&#xff09;提供比传统硬盘更快的读/写速度&#xff0c;使启动、软件加载和游戏启动更快。因此&#xff0c;在我们选择存储设备时&#xff0c;它是一个极好的选择。但是&#xff0c;它仍然存在数据丢失的风险。假设您是受害者之一&#xff0c;正在寻找…

SpringBoot的创建和使用

SpringBoot是什么&#xff1f;SpringBoot诞生的目的就是为了简化Spring开发&#xff0c;而相对于Spring&#xff0c;SpringBoot算是一个很大的升级&#xff0c;就如同汽车手动挡变成了自动挡。Spring&#xff1a;SpringBoot&#xff1a;SpringBoot的优点SpringBoot让Spring开发…

[技术选型] ClickHouse和StarRocks的介绍

文章目录1.ClickHouse介绍2.StarRocks介绍1.ClickHouse介绍 ClickHouse是面向联机分析处理&#xff08;OLAP&#xff09;的开源分析引擎。最初由俄罗斯第一搜索引擎Yandex开发&#xff0c;于2016年开源&#xff0c;开发语言为C。由于其优良的查询性能&#xff0c;PB级的数据规…

Linux的ACL(扩展权限)规划:setfacl、getfacl

目录 什么是ACL与如何支持启动ACL ACL设置技巧&#xff1a;getfacl、setfacl getfacl命令用法 setfacl命令用法 最简单的【u&#xff1a;账号&#xff1a;权限】设置 使用默认权限设置目录未来文件的ACL权限继承 什么是ACL与如何支持启动ACL ACL是Access Control List的…

【基础篇】7 # 队列:队列在线程池等有限资源池中的应用

说明 【数据结构与算法之美】专栏学习笔记 什么是队列&#xff1f; 队列是一种操作受限的线性表数据结构&#xff0c;特点是先进先出&#xff0c;最基本的操作有&#xff1a;入队 enqueue()&#xff0c;放一个数据到队列尾部&#xff1b;出队 dequeue()&#xff0c;从队列头…

综合保税区快速发展,卖家抓紧瞄准跨境电商

综合保税区指的是我国设立在内陆地区的海关特殊监管区域&#xff0c;具有报税港区的功能&#xff0c;这是由海关参照有关规定对综合保税区进行管理&#xff0c;执行保税港区的外汇政策和税收&#xff0c;集合众多功能于一身&#xff0c;包括保税区、保税物流区、出口加工区、港…