数据结构之图的分类和存储

图(Graph)G由两个集合V和E组成,记为:G=(V,E),其中V是顶点的有穷非空集合(其实就是顶点),E是V 中顶点偶对的有穷集合(就是)。V(G)和E(G)通常分别表示图G的顶点集合以及边集合,E(G)可以为空集合,但是此时的图只有顶点,没有边。

举个例子:

一个地图: 顶点:城市 边:路 可能只有城市没有路就是E(G)可以为空集合,图只有顶点,没有边。

多个城市 a b c d e

a 到b的方法(a到其他) :a - b a -c - b a - c - d - b

到a也有很多方法 b-a c-b-a 这样就形成了网状结构

1. 图的分类

  • 有向图:

边是有方向的。类似车道的单行道

这意味着每条边都从一个顶点指向另一个顶点,并且这种指向关系是有序的,有向图的 那个方向的线条称为。在有向图中,如果有一条从顶点A到顶点B的边,那么我们说A指向B(A是起点,B是终点),但这并不 意味着B也指向A

示例

在这里插入图片描述

  • 无向图

边没有方向。这意味着每条边都连接两个顶点,但不区分起点和终点。在无向图中,如果两个顶点由一 条边连接,那么它们是相邻的,并且这种相邻关系是对称的。

示例

在这里插入图片描述

  • 网(带权图)

如果在图的每条边(或者弧)都被赋予一个权重(常用于表示节点之间连接的成本或距离),即为 (带权图)

在这里插入图片描述

顶点的度

表示与顶点相连的边的数量。

  • 无向图

在这里插入图片描述

  • 有向图

在有向图中,顶点的度分为入度(In-degree)和出度(Out-degree)。

入度:指向该顶点的边的数量。

出度:从该顶点出发的边的数量。
在这里插入图片描述

  • 路径

图的路径是指由图中的顶点和边所构成的序列,其中顶点之间通过边相连。

两个顶点之间存在路径(到达方式),说明它们是连通

路径可以是有向的或无向 的,这取决于图的类型。

在这里插入图片描述

a->c连通 c->a不是因为 这是有向图c到a没有路径到达

若任意两个顶点之间都是连通的话,则图是连通图

在这里插入图片描述

这就是联通图

  • 邻接点

邻接点的定义是:如果两个顶点之间存在一条边,那么这两个顶点就互为邻接点

2 图的存储

2.1 邻接矩阵

矩阵(二维数组)

邻接矩阵是表示顶点间相邻关系的矩阵。

对于n个顶点的图,邻接矩阵是一个n×n的二维数组(只存储0 1)。两个顶点存在直接连接到边就是1,否则是0,自己到自己一般也是0

在无向图中,邻接矩阵是对称的(对于对角线对称),而在有向图中则不一定。

    • 无向图

在这里插入图片描述

对应的邻接矩阵是

12345
101001
210001
300011
400100
511100
    • 有向图

在这里插入图片描述

对应的邻接矩阵是

12345
101000
210001
300000
400100
510100

代码如下:

  • 有向图:
#include <iostream>
using namespace std;#define MAX_VERTICES 100 // 最大定点数// 初始化邻接矩阵  int(*p)[MAX_VERTICES]也可以数组指针
void initalizeGraph(int adjMartix[MAX_VERTICES][MAX_VERTICES], int n)
{for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){adjMartix[i][j] = 0; // 初始化为0,表示没有边}}
}// 添加有向边
void addDirectedEdge(int adjMartix[MAX_VERTICES][MAX_VERTICES], int u, int v) // uv是出度也是入度
{// 两目标直接连接 有向图adjMartix[u][v] = 1;// // 无向图// adjMartix[v][u]  = 1;
}
void printGraph(int adjMartix[MAX_VERTICES][MAX_VERTICES], int n)
{for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){printf("%d ", adjMartix[i][j]); // 初始化为0,表示没有边}printf("\n");}
}
//  打印图int main()
{int adjMartix[MAX_VERTICES][MAX_VERTICES]; // 图// 节点int n = 5;// 初始化图initalizeGraph(adjMartix, n);// 添加有向边addDirectedEdge(adjMartix, 0, 1);addDirectedEdge(adjMartix, 1, 0);addDirectedEdge(adjMartix, 1, 4);addDirectedEdge(adjMartix, 4, 0);addDirectedEdge(adjMartix, 4, 2);addDirectedEdge(adjMartix, 3, 2);// 打印有向图printGraph(adjMartix, n);return 0;
}

无向图:

#include <iostream>
using namespace std;#define MAX_VERTICES 100 // 最大定点数// 初始化邻接矩阵  int(*p)[MAX_VERTICES]也可以数组指针
void initalizeGraph(int adjMartix[MAX_VERTICES][MAX_VERTICES], int n)
{for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){adjMartix[i][j] = 0; // 初始化为0,表示没有边}}
}// 添加有向边
void addDirectedEdge(int adjMartix[MAX_VERTICES][MAX_VERTICES], int u, int v) // uv是出度也是入度
{// 两目标直接连接 有向图adjMartix[u][v] = 1;// // 无向图adjMartix[v][u]  = 1;
}
void printGraph(int adjMartix[MAX_VERTICES][MAX_VERTICES], int n)
{for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){printf("%d ", adjMartix[i][j]); // 初始化为0,表示没有边}printf("\n");}
}
//  打印图int main()
{int adjMartix[MAX_VERTICES][MAX_VERTICES]; // 图// 节点int n = 5;// 初始化图initalizeGraph(adjMartix, n);// 添加有向边addDirectedEdge(adjMartix, 0, 1);addDirectedEdge(adjMartix, 0, 4);addDirectedEdge(adjMartix, 1, 4);addDirectedEdge(adjMartix, 5, 3);addDirectedEdge(adjMartix, 3, 4);// 打印有向图printGraph(adjMartix, n);return 0;
}

优点:
编码简单,容易理解。
便于检查图中任意两个顶点之间是否存在边。
便于计算图中顶点的度。
缺点:
对于稀疏图,邻接矩阵会浪费大量存储空间,因为矩阵中的大部分元素都是0。
在进行图的遍历等操作时,可能需要遍历整个矩阵,效率较低。

2.2 邻接表

邻接表是图的一种链式存储结构。对于图中的每个顶点,邻接表都存储一个链表,该链表包含与该顶点相邻的所有顶点

例如下图1包含和他相邻的所有顶点,2和3

可以省略边:连接关系2-3(隐含表示边)(下节讲,下面的代码不省略)

1 - 2 - 3

1 - 3

在这里插入图片描述

代码如下

#include <iostream>
using namespace std;// 定义边
typedef struct EdgeNode
{int adjvex;            // 邻接点 终点struct EdgeNode *next; // 下一条边 个指针用于连接同一起点的多条边。这样,我们就可以通// 过遍历next指针来访问从A出发的所有边。
} EdgeNode;// 定义顶点
typedef struct VertexNode
{int data;            // 起点信息EdgeNode *FirstNode; // 这个指针用于从顶点出发找到其第一条边 。这样,我们就可以从任意一// 个顶点开始,通过firstedge找到其所有邻接点。
} VertexNode;typedef struct Grasp_List
{VertexNode *newNode; // 顶点int numVertices;     // 顶点数int numEdges;        // 边数
} Grasp_List;// 初始化函数
void InitGraph(Grasp_List *graph, int n)
{graph->newNode = new VertexNode[n](); // 分配内存 ()会进行初始化graph->numVertices = n;                顶点5graph->numEdges = 0;                  // 边0for (int i = 0; i < n; i++){graph->newNode[i].data = i;            // 初始化每个顶点的数据graph->newNode[i].FirstNode = nullptr; // 初始化第一条边为空}
}// 向图中添加边 u起始顶点 v邻接点
void AddEdge(Grasp_List *graph, int u, int v)
{// 创建边EdgeNode *newEdgeNode = (EdgeNode *)malloc(sizeof(EdgeNode)); // 创建新边节点// 分配失败if (!newEdgeNode){perror("分配失败");return;}newEdgeNode->adjvex = v; // 设置邻接点 也就是终点// 插入 头插法 把边直接newEdgeNode->next = graph->newNode[u].FirstNode; // 下一条边=原来的第一条边graph->newNode[u].FirstNode = newEdgeNode;       // 更新第一条边graph->numEdges++;                               // 边数加1如果是无向图 还需要再添加一条边// EdgeNode* newNodeV = (EdgeNode*)malloc(sizeof(EdgeNode)); // 创建新边节点// if (!newNodeV)//{//     printf("申请内存失败\n");//     exit(-1);// }// newNodeV->adjvex = u;                     // 设置邻接点头插法// newNodeV->next = G->adjList[v].firstedge; // 下一条边 = 原来的第一条边// G->adjList[v].firstedge = newNodeV;       // 更新第一条边
}// 打印邻接表
void printGraph(Grasp_List *graph)
{if (graph == nullptr){cout << "我是空图" << endl;return;}printf("Graph with %d vertices and  %d edge:\n", graph->numVertices, graph->numEdges);// 根据定点数遍历for (int i = 0; i < graph->numVertices; i++){printf("vertices %d: ", graph->newNode[i].data); // 打印顶点// 找到顶点第一条边EdgeNode *p = graph->newNode[i].FirstNode; // 保存while (p){// 邻接点printf(" %d", p->adjvex);// 下一条边p = p->next;}printf("\n");}
}// 释放图占用的内存
void freeGraph(Grasp_List *graph)
{if (graph == NULL){return;}// 释放边内存for (int i = 0; i < graph->numVertices; i++){EdgeNode *curerent = graph->newNode[i].FirstNode;EdgeNode *tmp = nullptr;while (curerent){tmp = curerent;curerent = curerent->next;free(tmp);tmp = nullptr;}curerent = nullptr;}// 释放顶点内存delete[] (graph->newNode);graph->newNode = nullptr;// 释放图本身的内存delete graph;
}// 主函数实例
int main()
{Grasp_List *G  = new Grasp_List;// 初始化图InitGraph(G, 5);// 添加边AddEdge(G, 0, 1);AddEdge(G, 0, 4);AddEdge(G, 1, 2);AddEdge(G, 1, 3);AddEdge(G, 2, 3);// 打印图printGraph(G);// 释放图freeGraph(G);return 0;
}

解释一个遍创建的过程

AddEdge(G, 0, 1);
  • 这表示在图 G 中添加一条从顶点 0 到顶点 1 的边。

  • 具体步骤如下:

    1. 创建一个新边节点 newEdgeNode,并为其分配内存。
    2. 将新边的邻接点设置为 1
    3. 使用头插法将新边插入到顶点 0 的边链表中,使新边成为顶点 0 的第一条边。
    4. 图的边数增加 1
  • 形成链表的过程

    在调用 AddEdge(G, 0, 1) 后,顶点 0 和顶点 1 通过一条边连接起来。具体来说:

    • 顶点 0 的边链表中新增了一个边节点,其 adjvex 字段为 1
    • 这个边节点通过 next 指针连接到原来顶点 0 的边链表

优点:
节省存储空间,特别是对于稀疏图。
便于添加和删除边。
便于进行图的遍历等操作。

缺点:
不便于检查图中任意两个顶点之间是否存在边(需要遍历两个顶点的邻接表)。
在某些情况下,可能需要额外的空间来存储顶点的信息(如顶点的索引或名称)。

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

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

相关文章

扩增子分析|微生物生态网络稳定性评估之鲁棒性(Robustness)和易损性(Vulnerability)在R中实现

一、引言 周集中老师团队于2021年在Nature climate change发表的文章&#xff0c;阐述了网络稳定性评估的原理算法&#xff0c;并提供了完整的代码。自此对微生物生态网络的评估具有更全面的指标&#xff0c;自此网络稳定性的评估广受大家欢迎。本系列将介绍网络稳定性之鲁棒性…

setup 函数在 Vue 3 中的作用是什么?什么时候会执行

文章目录 前言✅ 一、setup() 函数的作用是什么&#xff1f;✅ 二、setup() 什么时候执行&#xff1f;✅ 三、setup() 的参数✅ 四、setup() 中不能做什么&#xff1f;✅ 五、常见用法示例✅ 六、总结&#xff08;适合背诵或面试回答&#xff09; <script setup> 是 **Vu…

JDBC实现--保姆级教程~

本来以为写过一个使用python与数据库连接的文章&#xff0c;但是今天突然发现没有&#xff0c;那就直接写Java与数据库连接的吧。当然如果大家有需要可以告诉我&#xff0c;有时间的话也可以写一个的pymysql的使用的。 数据库有很多种&#xff0c;接下来我就以MySQL为例来进行讲…

Ubuntu18.04搭建samda服务器

一.什么是Samba服务器&#xff1f; Samba服务器是一种基于开源协议实现的网络共享服务软件&#xff0c;主要用于在不同操作系统&#xff08;如Windows、Linux、Unix&#xff09;之间实现文件和打印机共享功能。其核心目标是解决跨平台资源共享的兼容性问题&#xff0c;尤其是在…

《分词算法大揭秘:BPE、BBPE、WordPiece、ULM常见方法介绍》

分词算法是自然语言处理&#xff08;NLP&#xff09;中的一个重要预处理步骤&#xff0c;它将文本分割成更小的单元&#xff08;如单词、子词或字符&#xff09;。以下是几种常见的分词算法&#xff1a;Byte Pair Encoding (BPE)、Byte-level BPE (BBPE)、WordPiece 和 Unigram…

WordPress01 - 后台常用功能

最近些日子研究Wordpress&#xff0c;做些简单的笔记。 怎么安装Wordpress&#xff0c;怎么进的后台&#xff0c;这些咱就不唠了哈&#xff0c;网上到处是教程。 目录 1&#xff0c;Wordpress的后台 1-1&#xff0c; Posts(投稿) 1-2&#xff0c;Media(媒体) 1-3&#xf…

R8周:RNN实现阿尔茨海默病诊断

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客 &#x1f356; 原作者&#xff1a;K同学啊 一、前期准备 1.设置GPU import numpy as np import pandas as pd import torch from torch import nn import torch.nn as nn import torch.nn.functi…

今天python练习题

目录 一、每日一言 二、练习题 三、效果展示 四、下次题目 五、总结 一、每日一言 不要害怕失败&#xff0c;失败可能成为我们前进的动力&#xff01; 二、练习题 有列表lst [[1,2,3],[4,5,6],[7,8,9]],取出其中的元素1/5/9组成新的列表 # 有列表lst [[1,2,3],[4,5,6],[…

机器人强化学习入门学习笔记(二)

基于上一篇的《机器人强化学习入门学习笔记》,在基于 MuJoCo 的仿真强化学习训练中,除了 PPO(Proximal Policy Optimization)之外,还有多个主流强化学习算法可用于训练机器人直行或其他复杂动作。 🧠 一、常见强化学习算法对比(可用于 MuJoCo) 算法类型特点适合场景PP…

用 DuckDB 高效分析 JSON 数据:从入门到实战

解析 JSON 文件进行分析常常充满挑战。无论你是在处理 API 响应、日志文件&#xff0c;还是应用数据&#xff0c;如果没有合适的工具&#xff0c;分析 JSON 都会非常耗时。 借助 DuckDB&#xff0c;你可以直接用 SQL 查询复杂的 JSON 文件&#xff0c;无需编写复杂的解析代码或…

从贴牌到品牌:出海官网如何让中国制造“贵”起来?

在全球经济一体化的当下&#xff0c;中美关税战如同一记重锤&#xff0c;给国际贸易格局带来了巨大震荡。自贸易摩擦爆发以来&#xff0c;双方多次调整关税政策&#xff0c;涉及的商品种类不断增多&#xff0c;税率持续攀升&#xff0c;众多中国企业的出口业务遭受重创&#xf…

react-13react中外部css引入以及style内联样式(动态className与动态style)

1. 外部css文件 - 普通引入 1.1 创建一个 CSS 文件&#xff0c;MyComponent.css。 /* MyComponent.css */ .my-class {color: red;font-size: 20px; } 1.2 组件中import引入 import React from react; import ./MyComponent.css; // 引入 CSS 文件function MyComponent() {r…

n8n 与智能体构建:开发自动化 AI 作业的基础平台

n8n 是一款开源的自动化流程构建平台&#xff0c;通过其模块化节点系统&#xff0c;开发者可以快速实现跨平台的任务编排、数据集成与智能交互。当 n8n 与大型语言模型&#xff08;LLM&#xff09;结合时&#xff0c;就能构建出具备感知、推理、执行能力的 AI 智能体&#xff0…

14.Spring Boot 3.1.5 集成 Spring Security 进行访问控制

14.Spring Boot 3.1.5 集成 Spring Security 进行访问控制 Spring Security 是一个强大且高度可定制的认证和访问控制框架&#xff0c;专为基于 Spring 的应用程序设计。它为基于 Java EE 的企业应用程序提供了全面的安全解决方案&#xff0c;包括 Web 应用程序安全和方法级安…

Linux学习笔记(二):Linux权限管理

文章目录 一、Linux下用户的分类1. Linux下用户分为两类&#xff1a;2. 这两类用户如何进行切换呢&#xff1f;3. 短暂提权 二、何为权限1. 什么是权限2. Linux的文件后缀意义 三、修改权限1. 设置文件的访问权限——chmod2. 修改文件拥有者——chown3. 修改文件所属组——chgr…

学习alpha,第2个alpha

alphas (-1 * ts_corr(rank(ts_delta(log(volume), 2)), rank(((close - open) / open)), 6)) 先分析操作符从左到右 ts_corr: Pearson 相关度量两个变量之间的线性关系。当变量呈正态分布且关系呈线性时&#xff0c;它最有效。 ts_corr(vwap, close, 20)是一个计算时间序列相…

Paddle Serving|部署一个自己的OCR识别服务器

前言 之前使用C部署了自己的OCR识别服务器&#xff0c;Socket网络传输部分是自己写的&#xff0c;回过头来一看&#xff0c;自己犯傻了&#xff0c;PaddleOCR本来就有自己的OCR服务器项目&#xff0c;叫PaddleServing&#xff0c;这里记录一下部署过程。 1 下载依赖环境 1.1 …

React Native【详解】搭建开发环境,创建项目,启动项目

下载安装 node https://nodejs.cn/download/ 查看 npx 版本 npx -v若无 npx 则安装 npm install -g npx创建项目 npx create-expo-applatestRN_demo 为自定义的项目名称 下载安装 Python 2.7 下载安装 JAVA JDK https://www.oracle.com/java/technologies/downloads/#jdk24-…

NVIDIA Halos:智能汽车革命中的全栈式安全系统

高级辅助驾驶行业正面临一个尴尬的"安全悖论"——传感器数量翻倍的同时&#xff0c;事故率曲线却迟迟不见明显下降。究其原因&#xff0c;当前行业普遍存在三大技术困局&#xff1a; 碎片化安全方案 传统方案就像"打补丁"&#xff0c;激光雷达厂商只管点云…

数据资产管理与AI融合:物联网时代的新征程

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;数据资产已成为企业和组织的核心竞争力之一。随着物联网&#xff08;IoT&#xff09;技术的飞速发展&#xff0c;海量的数据如潮水般涌来&#xff0c;如何高效地管理和利用这些数据资产成为了亟待解决的问题。与此同时&am…