C++ 数据结构图(1)

news2024/12/29 9:56:23

1. 图的基本概念

        

                图是由顶点集合及顶点间的关系组成的一种数据结构:G = (V, E) ,其中:
 顶点集合 V = {x|x 属于某个数据对象集 } 是有穷非空集合 E = {(x,y)|x,y 属于 V} 或者 E = {<x, y>|x,y 属于 V && Path(x, y)} 是顶点间关系的有穷集合,也叫 做边的集合 。 (x, y)表示 x y 的一条双向通路,即 (x, y) 是无方向的; Path(x, y) 表示从 x y 的一条单向通路,即 Path(x, y)是有方向的。顶点和边:图中结点称为顶点 ,第 i 个顶点记作 vi 两个顶点 vi vj 相关联称作顶点 vi 和顶点 vj 之间 有一条边 ,图中的第 k 条边记作 ek ek = (vi vj) <vi vj> 。有向图和无向图:在有向图中,顶点对 <x, y> 是有序的,顶点对 <x y> 称为顶点 x 到顶点 y 的一条 ( ) <x, y> <y, x> 是两条不同的边 ,比如下图 G3 G4 为有向图。在 无向图中,顶点对 (x, y) 是无序的,顶点对 (x,y) 称为顶点 x 和顶点 y 相关联的一条边,这条边没有特定方向, (x, y) (y x) 是同一条边 ,比如下图 G1 G2 为无向图。注意: 无向边 (x, y) 等于有向边 <x, y> <y, x>

完全图:在 n 个顶点的无向图中 ,若 n * (n-1)/2 条边 ,即 任意两个顶点之间有且仅有一条边
则称此图为 无向完全图 ,比如上图 G1 ;在 n 个顶点的有向图 中,若 n * (n-1) 条边 ,即 任意两个
顶点之间有且仅有方向相反的边 ,则称此图为 有向完全图 ,比如上图 G4
邻接顶点:在 无向图中 G 中,若 (u, v) E(G) 中的一条边,则称 u v 互为邻接顶点 ,并称 (u,v)
附于顶点 u v ;在 有向图 G 中,若 <u, v> E(G) 中的一条边,则称顶点 u 邻接到 v ,顶点 v 邻接自顶
u ,并称边 <u, v> 与顶点 u 和顶点 v 相关联
顶点的度: 顶点 v 的度是指与它相关联的边的条数,记作 deg(v) 。在有向图中, 顶点的度等于该顶
点的入度与出度之和 ,其中顶点 v 入度是以 v 为终点的有向边的条数 ,记作 indev(v); 顶点 v 出度
是以 v 为起始点的有向边的条数 ,记作 outdev(v) 。因此: dev(v) = indev(v) + outdev(v) 。注
意:对于 无向图,顶点的度等于该顶点的入度和出度 ,即 dev(v) = indev(v) = outdev(v) 。路径:在图G = (V E) 中,若 从顶点 vi 出发有一组边使其可到达顶点 vj ,则称顶点 vi 到顶点 vj 的顶 点序列为从顶点 vi 到顶点 vj 的路径 。路径长度:对于不带权的图,一条路径的路径长度是指该路径上的边的条数 ;对于 带权的图,一 条路 径的路径长度是指该路径上各个边权值的总和

简单路径与回路: 若路径上各顶点 v1 v2 v3 vm 均不重复,则称这样的路径为简单路
若路 径上第一个顶点 v1 和最后一个顶点 vm 重合,则称这样的路径为回路或环

子图: 设图 G = {V, E} 和图 G1 = {V1 E1} ,若 V1 属于 V E1 属于 E ,则称 G1 G 的子图

连通图:在 无向图 中,若从顶点 v1 到顶点 v2 有路径,则称顶点 v1 与顶点 v2 是连通的。 如果图中任
意一 对顶点都是连通的,则称此图为连通图
强连通图:在 有向图 中,若在 每一对顶点 vi vj 之间都存在一条从 vi vj 的路径,也存在一条从 vj
vi 的路径,则称此图是强连通图
生成树:一个 连通图的最小连通子图 称作该图的生成树。 n 个顶点的连通图的生成树有 n 个顶点
n- 1 条边。

2. 图的存储结构

因为图中既有节点,又有边 ( 节点与节点之间的关系 ) ,因此, 在图的存储中,只需要保存:节点和
边关系即可 。节点保存比较简单,只需要一段连续空间即可,那边关系该怎么保存呢?

2.1 邻接矩阵

因为节点与节点之间的关系就是连通与否,即为 0 或者 1 ,因此 邻接矩阵 ( 二维数组 ) 即是:先用一
个数组将定点保存,然后采用矩阵来表示节点与节点之间的关系

注意:
1. 无向图的邻接矩阵是对称的 i ( ) 元素之和,就是顶点 i 的度 有向图的邻接矩阵则不一 定是对称的,第 i ( ) 元素之后就是顶点 i 的出 ( )
2. 如果边带有权值,并且两个节点之间是连通的,上图中的边的关系就用权值代替,如果两个顶点不通,则使用无穷大代替。

3. 用邻接矩阵存储图的有点是能够快速知道两个顶点是否连通,缺陷是如果顶点比较多,边比较少时,矩阵中存储了大量的0 成为系数矩阵,比较浪费空间,并且要求两个节点之间的路径不是很好求。

#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

template <class V, class W, W MAX_W = INT_MAX, bool Direction = false>
class Graph
{
public:
    typedef Graph<V, W, MAX_W, Direction> Self;
    Graph() = default;
    Graph(const V *vertexs, size_t n)
    {
        _vertexs.reserve(n);
        for (size_t i = 0; i < n; ++i)
        {
            _vertexs.push_back(vertexs[i]);
            _vIndexMap[vertexs[i]] = i;
        }
        // MAX_W 作为不存在边的标识值
        _matrix.resize(n);
        for (auto &e : _matrix)
        {
            e.resize(n, MAX_W);
        }
    }
    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(size_t srci, size_t dsti, const W &w)
    {
        _matrix[srci][dsti] = w;
        if (Direction == false)
        {
            _matrix[dsti][srci] = w;
        }
    }
    void AddEdge(const V &src, const V &dst, const W &w)
    {
        size_t srci = GetVertexIndex(src);
        size_t dsti = GetVertexIndex(dst);
        _AddEdge(srci, dsti, w);
    }

    void Print()
    {
        // 打印顶点和下标映射关系
        for (size_t i = 0; i < _vertexs.size(); ++i)
        {
            cout << _vertexs[i] << "-" << i << " ";
        }
        cout << endl
             << endl;
        cout << " ";
        for (size_t i = 0; i < _vertexs.size(); ++i)
        {
            cout << i << " ";
        }
        cout << endl;
        // 打印矩阵
        for (size_t i = 0; i < _matrix.size(); ++i)
        {
            cout << i << " ";
            for (size_t j = 0; j < _matrix[i].size(); ++j)
            {
                if (_matrix[i][j] != MAX_W)
                    cout << _matrix[i][j] << " ";
                else
                    cout << "#"
                         << " ";
            }
            cout << endl;
        }
        cout << endl
             << endl;
        // 打印所有的边
        for (size_t i = 0; i < _matrix.size(); ++i)
        {
            for (size_t j = 0; j < _matrix[i].size(); ++j)
            {
                if (i < j && _matrix[i][j] != MAX_W)
                {
                    cout << _vertexs[i] << "-" << _vertexs[j] << ":" << _matrix[i][j] << endl;
                }
            }
        }
    }

private:
    map<V, size_t> _vIndexMap;
    vector<V> _vertexs; // 顶点集合
    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();
}

int main()
{
    TestGraph();
    system("pause");
    return 0;
}

2.2 邻接表

邻接表:使用数组表示顶点的集合,使用链表表示边的关系

1. 无向图邻接表存储

注意: 无向图中同一条边在邻接表中出现了两次。如果想知道顶点 vi 的度,只需要知道顶点 vi 边链表集合中结点的数目即可
2. 有向图邻接表存储

注意:有向图中每条边在邻接表中只出现一次,与顶点 vi 对应的邻接表所含结点的个数,就是该顶点的出度,也称出度表,要得到vi 顶点的入度,必须检测其他所有顶点对应的边链表,看有多少边顶点的dst 取值是 i
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

namespace LinkTable
{

    template <class W>
    struct LinkEgde
    {
        int _srcIndex;
        int _dstIndex;
        W _w;
        LinkEgde<W> *_next;

        LinkEgde(const W &w) : _srcIndex(-1), _dstIndex(-1), _w(w), _next(nullptr) {}
    };

    template <class V, class W, bool Direction = false>
    class Graph
    {

        typedef LinkEgde<W> Edge;

    public:
        Graph(const V *vertexs, size_t n)
        {

            _vertexs.reserve(n);
            for (size_t i = 0; i < n; i++)
            {

                _vertexs.push_back(_vertexs[i]);
                _vIndexMap[_vertexs[i]] = i;
            }
            _linkTable.resize(n, nullptr);
        }
        size_t GetVertexIndex(const V &v)
        {

            auto ret = _vIndexMap.find(v);
            if (ret != _vIndexMap.end())
            {
                return ret->second;
            }
            else
            {
                throw invalid_argument("not exist vertex");
                return -1;
            }
        }

        void AddEdge(const V &src, const V &dst, const W &w)
        {

            size_t srcindex = GetVertexIndex(src);
            size_t dstindex = GetVertexIndex(dst);

            Edge *sd_edge = new Edge(w);
            sd_edge->_srcIndex = srcindex;
            sd_edge->_dstIndex = dstindex;
            sd_edge->_next = _linkTable[srcindex];
            _linkTable[srcindex] = sd_edge;

            //如果是无向图

            if (Direction == false)
            {

                Edge *ds_edge = new Edge(w);
                ds_edge->_srcIndex = dstindex;
                ds_edge->_dstIndex = srcindex;
                ds_edge->_next = _linkTable[dstindex];
                _linkTable[dstindex] = ds_edge;
            }
        }

    private:
        map<string, int> _vIndexMap;
        vector<V> _vertexs;        //顶点集合
        vector<Edge *> _linkTable; //边的集合
    };

    void TestGraph()
    {

        string a[] = {"zhangsan", "lisi", "wangwu", "zhaoliu"};
        Graph<string, int> g1(a, 4);
        g1.AddEdge("zhangsan", "lisi", 100);
        g1.AddEdge("zhangsan", "wangwu", 200);
        g1.AddEdge("wangwu", "zhaoliu", 30);
    }

}

int main()
{

    LinkTable::TestGraph();

    system("pause");
    return 0;
}

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

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

相关文章

【Spring Boot 事务】万字详解Spring Boot 事务,赶快跟随良辰一起去学习Spring Boot 事务吧! ! !

前言: 大家好,我是良辰丫,这篇文章我将带领大家一起去学习Spring Boot 事务文章,我们在学习数据库的时候已经接触过事务了,来跟随我的脚步一起来瞧一下Spring Boot 事务吧.&#x1f48c;&#x1f48c;&#x1f48c; &#x1f9d1;个人主页&#xff1a;良辰针不戳 &#x1f4d6;…

得物社区推荐精排模型演进

1.背景 得物社区是一大批年轻人获取潮流信息、分享日常生活的潮流生活社区。其中用户浏览的信息&#xff0c;进行个性化的分发&#xff0c;是由推荐系统来决策完成的。目前得物社区多个场景接入了推荐算法&#xff0c;包括首页推荐双列流、沉浸式视频推荐、分类tab推荐流、直播…

Tomcat的安装部署及优化

tomcat安装部署 tomcat安装部署 一、概述&#xff1a;1.tomcat介绍&#xff1a;2.tomcat核心组件&#xff1a;3.tomcat处理内部请求&#xff08;数据流向图&#xff09;4.tomcat服务部署&#xff1a; 二、虚拟主机配置&#xff1a;1.创建 chan 和 baek 项目目录和文件&#xf…

Python常见的开发工具合集对比

​ Python是一种功能强大且易于学习的编程语言&#xff0c;被广泛应用于数据科学、机器学习、Web开发等领域。随着Python在各个领域的应用越来越广泛&#xff0c;越来越多的Python开发工具也涌现出来。但是&#xff0c;对于新手来说&#xff0c;选择一款合适的Python开发工具可…

BurpSutie拓展插件推荐-漏洞扫描插件

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 fastjsonScan&#xff08;1&#xff09;工具介绍&#xff08;2&#xff09;下载地址&#xff08;3&#xff09;使用说明 02 SpringScan&#xff08;1&#xff09;工具介绍&#xff08;2&#xff09…

python接口自动化(十三)--cookie绕过验证码登录(详解)

简介 有些登录的接口会有验证码&#xff1a;短信验证码&#xff0c;图形验证码等&#xff0c;这种登录的话验证码参数可以从后台获取的&#xff08;或者查数据库最直接&#xff09;。获取不到也没关系&#xff0c;可以通过添加cookie的方式绕过验证码。&#xff08;注意&#x…

GPT模型训练实践(1)-基础概念

GPT 是 Generative Pre-trained Transformers 的缩写&#xff0c;一种先进的深度学习模型&#xff0c;旨在生成类人文本。GPT 的三个组成部分Generative、Pre-trained 和 Transformer&#xff0c;其解释如下&#xff1a; Generative生成&#xff1a;生成模型是用于生成新数据的…

【DASOU视频记录】Transformer从零详细解读

文章目录 来源transformer的全局理解位置编码多头注意力机制残差Batch NormalLayer NormalDecoder 来源 b站链接 transformer的全局理解 输入中文&#xff0c;输出英文 细化容易理解的结构&#xff0c;就是先编码&#xff0c;再解码 进一步细化的结构&#xff0c;就是多个编…

Python_闭包

目录 1.概念介绍 2.闭包初探 3.闭包陷阱 4.闭包的应用 4.1 潜在的问题 5.闭包的实现 闭包并不只是一个python中的概念&#xff0c;在函数式编程语言中应用较为广泛。理解python中的闭包一方面是能够正确的使用闭包&#xff0c;另一方面可以好好体会和思考闭包的设计思想。…

面试又问到:工作中发现的最有价值的bug?答不好offer要飞了...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 这个问题&#xf…

SpringBoot--超时熔断器

需求背景 如果一个服务中有很多涉及需要服务间熔断的地方&#xff0c;就会出现N多下述代码&#xff1a; 1.N个fegnClient接口 FeignClient(name "hello-world-service", fallback HelloWorldFallback.class) public interface HelloWorldService {GetMapping(&q…

gma 2 教程(一)概述:3. 探索 GMA

组织方式 gma 整体按照库-模块-类/函数-&#xff08;方法/属性/子类&#xff09;的思路构建&#xff0c;详细思路如下所示&#xff1a; 整体架构 gma内主要模块与功能对应关系见下表&#xff1a; 模块名中文名对应主要功能io输入输出栅格/矢量数据输入输出模块crs坐标系统坐…

vim的使用方法及相关按键

目录 一、安装vim 二、vim的使用 1.打开vim 2.vim的四种模式使用 &#xff08;1&#xff09;命令模式&#xff08;快捷键的使用&#xff09; &#xff08;2&#xff09;编辑模式 &#xff08;3&#xff09;末行模式 &#xff08;4&#xff09;可视化模式 一、安装vim …

022:vue中tree结构数据变成扁平化table结构数据的示例

第022个 查看专栏目录: VUE — element UI vue在使用element UI tree的时候,有的时候是要做逆向处理的,即将树形结构的数据转化为table结构的数据,即扁平化的json数据。 如何处理呢? 效果图 原始tree结构数据: let newdata= [ {

redis pipeline

redis 执行多条连续的命令的时候为了减少网络开销RTT&#xff0c;可以使用pipeline技术。 pipeline 与 原生批命令(mset, mget) 对比&#xff1a; 原生批命令是原子性&#xff0c;pipeline是非原子性 (原子性概念:一个事务是一个不可分割的最小工作单位,要么都成功要么都失败…

基于Anime2Sketch算法那将图片转成素描

1.下载源码地址 https://github.com/Mukosame/Anime2Sketch下载项目依赖包&#xff0c;下载模型权重文件 运行看效果 python test.py --datarootE:\01_hjz\datas\00-hjz\pictures --load_size512调整自定义测试图片路径 """Test script for anime-to-sketch…

基于Java+Vue前后端分离网上书城系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

ChatGPT+低代码,好用到飞起?

ChatGPT 凭借短短 2 个月&#xff0c;月活用户突破 1 亿&#xff0c;成为史上用户增长速度最快的消费级应用程序。ChatGPT 的爆火&#xff0c;在全球范围内掀起了一场关于 AI 技术革命的狂潮&#xff0c;AIGC 也迅速成为科技圈最火赛道。 更有国际咨询机构预测&#xff0c;203…

IIS安装配置和简单网站部署流程

IIS安装和网站配置 环境&#xff1a;win10 注意&#xff1a;这是在win10下部署iis&#xff0c;开发环境下部署&#xff0c;开发测试&#xff0c;非windows server IIS简介 Internet Information Services,简称IIS&#xff0c;是微软提供基于windows的互联网信息服务&#x…

微信小程序使用第三方组件wxParse加载富文本html

微信小程序使用第三方组件wxParse加载富文本html 微信小程序微信小程序加载富文本html微信小程序富文本第三方组件wxParsewxParse富文本html wxParse简介 wxParse 是一个微信小程序富文本解析组件&#xff0c;支持支持Html及markdown转wxml。 wxParse gitHub地址&#xff1…