数据结构--》连接世界的无限可能—— 图

        图作为数据结构中的一种重要概念,扮演着连接世界的纽带。与树和二叉树相比,图更加灵活和多样化,它能够描述各种实际问题中的复杂关系,如社交网络中的人际联系、城市交通中的路线规划以及电子网络中的通信路径等。

        无论你是初学者还是进阶者,本文将为你提供简单易懂、实用可行的知识点,帮助你更好地掌握图在数据结构和算法中的重要性,进而提升算法解题的能力。接下来让我们开启数据结构与算法的奇妙之旅吧。

目录

图的基本概念

图的存储表示

图的基本操作

图的遍历与连通性

最小生成树 

最短路径问题

关键路径问题


图的基本概念

图是由一组顶点(节点)和连接这些顶点的边(关系)组成的非线性数据结构。图用于表示元素之间的关系,通过节点和边来描述图中元素之间的连接情况。

图的定义包括以下几个要素

顶点:图中的节点表示实体或对象,通常用圆圈或方框来表示。每个节点可以包含一些相关信息,如名称、属性等。

:图中的边表示顶点之间的关系,用于连接不同的顶点。边可以是有向的(箭头表示方向)或无向的(不带箭头表示),也可以带有权重(表示边的权值)。

邻接点:对于一个顶点,与它直接相连的顶点称为邻接点。邻接点之间通过边相连。

路径:路径是指顶点之间经过的一系列边的序列。路径的长度可以通过经过的边的数量来计算。

:如果路径的起点和终点是同一个顶点,并且至少经过了一条边,就形成了一个圈。圈也被称为循环。

有向图和无向图

顶点的度

对于无向图而言,顶点v的度是指依附于该顶点的边的条数,记为TD(v)。

对于有向图而言,我们要探讨的是顶点的入度和出度:

顶点v的度等于入度和出度之和,即 TD(v) = ID(v) + OD(v)。

入读是以顶点v为终点的有向边的数目,记为ID(V);出度是以顶点v为起点的有向边的数目,记为OD(v)。

顶点与顶点之间的关系描述

连通图和强连通图

子图:(研究图的局部)

对于有向图来说子图和生成子图的概念也是一样的:

连通分量

无向图中的极大连通子图称为连通分量:

有向图中的极大强连通子图称为有向图的强连通分量:

生成树

连通图的生成树是包含图中全部顶点的一个极小连通子图。

生成森林

在非连通图中,连通分量的生成树构成了非连通图的生成森林。

几种特殊形态的图

回顾重点,其主要内容整理成如下内容:

图的存储表示

图可以用多种方式进行存储表示,常见的有两种主要方法:邻接矩阵和邻接表。

邻接矩阵法

邻接矩阵是一个二维数组,用于表示图中的节点之间的连接关系。对于一个有n个节点的图,邻接矩阵是一个大小为n×n的方阵。如果节点i和节点j之间存在一条边,则邻接矩阵中第i行第j列的元素为1;否则为0。邻接矩阵的优点是可以快速判断任意两个节点之间是否有边,但缺点是当图比较稀疏时会占用大量的空间。

如果我们采用邻接矩阵法存储带权图(网):

邻接表法

根据有向无向连判断当前结点所连接的下一个结点的索引:

回顾重点,其主要内容整理成如下内容: 

十字链表法存储有向图

邻接多重表存储无向图

如果删除结点和边的话得到的相应结果如下:

回顾重点,其主要内容整理成如下内容:

图的基本操作

如果我们想知道两个结点之间是否存在边可以通过邻接矩阵或者邻接表的方式:

如果我们想在图中插入顶点x,可以采用如下的方式进行:

如果想在图中删除某个顶点x,可以采用如下的方式进行:

如果想知道图中顶点x的第一个邻接点,若有则返回顶点号,若x没有邻接点或图中不存在x,则返回-1:

图的遍历与连通性

图的遍历是指访问图中所有节点的过程。通过遍历,我们可以对图的结构和节点之间的关系进行全面的了解。常用的图遍历算法包括广度优先搜索(BFS)和 深度优先搜索(DFS)。

广度优先遍历:图的广度优先遍历(Breadth-First Search,BFS)是一种从起始节点开始,先访问离起点最近的节点,然后逐层向外扩展访问的策略。它保证了先访问距离起始节点相近的节点,然后再访问距离稍远的节点。

广度优先遍历序列的案例如下:

下面是用 C 语言实现图的广度优先遍历的基本代码示例:

#include <stdio.h>#define MAX_NODES 100typedef struct {int neighbor[MAX_NODES];int numNeighbors;int visited;
} Node;void bfs(Node graph[], int start, int numNodes) {int queue[MAX_NODES];int front = 0, rear = 0;// 将起始节点加入队列并标记为已访问queue[rear++] = start;graph[start].visited = 1;while (front != rear) {int current_node = queue[front++];  // 队首节点出队printf("%d ", current_node);  // 访问当前节点// 遍历当前节点的邻居节点for (int i = 0; i < graph[current_node].numNeighbors; i++) {int neighbor = graph[current_node].neighbor[i];if (!graph[neighbor].visited) {  // 如果邻居节点未被访问过queue[rear++] = neighbor;  // 将邻居节点入队graph[neighbor].visited = 1;  // 标记邻居节点为已访问}}}
}int main() {// 创建一个示例图Node graph[MAX_NODES];// 初始化图中的节点和边for (int i = 0; i < MAX_NODES; i++) {graph[i].numNeighbors = 0;graph[i].visited = 0;}// 添加边关系graph[0].neighbor[graph[0].numNeighbors++] = 1;graph[0].neighbor[graph[0].numNeighbors++] = 2;graph[1].neighbor[graph[1].numNeighbors++] = 3;graph[2].neighbor[graph[2].numNeighbors++] = 4;graph[2].neighbor[graph[2].numNeighbors++] = 5;graph[3].neighbor[graph[3].numNeighbors++] = 6;graph[4].neighbor[graph[4].numNeighbors++] = 7;// 进行广度优先遍历bfs(graph, 0, 8);  // 假设图中有 8 个节点return 0;
}

广度优先生成树用于在一个无向图或有向图中从给定的起始节点开始,以广度优先的方式生成一个树状结构,该树包含了从起始节点出发到达所有可达节点的最短路径。 

回顾重点,其主要内容整理成如下内容:

深度优先遍历:深度优先搜索(Depth-First Search,DFS)是一种先走尽可能远的策略,即沿着当前路径走到底,直到不能再走下去为止,然后回溯到前一个节点,继续探测其他路径,直到所有节点都被访问过。

深度优先生成树是指通过深度优先搜索算法生成的一棵树状结构,该树包含了从给定起始节点出发到达所有可达节点的最短路径。

下面是用 C 语言实现深度优先遍历的基本代码示例:

#include <stdio.h>#define MAX_NODES 100typedef struct {int neighbor[MAX_NODES];int numNeighbors;int visited;
} Node;void dfs(Node graph[], int current_node) {printf("%d ", current_node);  // 先访问当前节点graph[current_node].visited = 1;  // 标记当前节点为已访问// 遍历当前节点的邻居节点,递归调用 dfs 函数for (int i = 0; i < graph[current_node].numNeighbors; i++) {int neighbor = graph[current_node].neighbor[i];if (!graph[neighbor].visited) {  // 如果邻居节点未被访问过dfs(graph, neighbor);  // 递归访问邻居节点}}
}int main() {// 创建一个示例图Node graph[MAX_NODES];// 初始化图中的节点和边for (int i = 0; i < MAX_NODES; i++) {graph[i].numNeighbors = 0;graph[i].visited = 0;}// 添加边关系graph[0].neighbor[graph[0].numNeighbors++] = 1;graph[0].neighbor[graph[0].numNeighbors++] = 2;graph[1].neighbor[graph[1].numNeighbors++] = 3;graph[2].neighbor[graph[2].numNeighbors++] = 4;graph[2].neighbor[graph[2].numNeighbors++] = 5;graph[3].neighbor[graph[3].numNeighbors++] = 6;graph[4].neighbor[graph[4].numNeighbors++] = 7;// 进行深度优先遍历dfs(graph, 0);  // 假设从节点 0 开始遍历return 0;
}

连通分量

连通分量是指一个无向图中的最大连通子图。连通分量由若干个顶点及它们之间的边组成,其中每个顶点都可以通过路径与其他顶点相互到达。

在无向图中,连通分量可以非常直观地理解为图中的一片区域,该区域中的所有顶点都可以彼此到达。每个连通分量都是图的一部分,并且一个图可以有多个连通分量。

在有向图中,连通分量的定义相对复杂一些。有向图的连通性需要考虑顶点之间的有向路径。有向图中的连通分量是指在该图中,每个顶点都存在至少一条有向路径可以到达其他所有顶点。

回顾重点,其主要内容整理成如下内容: 

最小生成树 

最小生成树是指在无向带权连通图中,寻找一棵包含所有顶点的生成树,并且该树的所有边的权值之和最小。最小生成树有以下特点:

最小生成树可能是多个;最小生成树中的边数等于顶点数减1;最小生成树中不会有回路。

常见的解决最小生成树问题的算法包括 Prim算法Kruskal算法

Prim算法(普里姆):从某一个顶点开始构建生成树;每次将代价最小的新顶点纳入生成树,直到所有的顶点都纳入为止。

这里我们选择p城为根结点,然后依次向外扩张找连线之间代价最小的结点,最终得到最小代价:

Kruskal算法(克鲁斯卡尔):每次选择一条权值最小的边,使这条边的两头连通(原本已经连通的就不选)直到所有的结点都连通。

两种算法的比较:

最短路径问题

图的最短路径问题是指在一个加权有向图或无向图中,寻找两个顶点之间最短路径的问题。最短路径可以通过边的权值和来衡量。最短路径问题主要分为以下两种情况:

单源最短路径:从给定的一个起始节点到图中其他所有节点之间的最短路径。它可以用于解决从一个固定起点到其他节点的最短路径问题。

BFS算法(无权图):

Dijkstra算法(带权图、无权图):

各顶点间的最短路径:计算图中任意两个节点之间的最短路径。它可以用于解决任意节点对之间的最短路径问题。

Floyd算法(带权图、无权图):

回顾重点,其主要内容整理成如下内容:  

关键路径问题

关键路径是指项目计划中不能延误的最长路径,它决定了整个项目的最短完成时间。关键路径问题常用于项目管理和工程规划中。

在AOE网中我们要了解以下概念:

根据上文相关例子的举出之后,接下来我们开始计算相应的数值:

求所有事件的最早发生时间:(等最慢的完成才可以)

求所有事件的最迟发生事件:(汇点的最迟发生时间与最早发生时间一致,我们以汇点为触发点你拓扑排序,即减去相应路径上发生的事件从而得到该点的最迟发生时间):

求所有活动的最早发生时间:(通过前面计算处的事件最早发生时间推算出活动最早发生时间):

求所有活动的最晚发生时间:(通过前面计算处的事件最迟发生时间减去相应活动需要的时间得出)

求所有活动的时间余量:(活动最晚发生时间减去活动最早发生时间)

注意:以下是相应的关键活动和关键路径的特性:

回顾重点,其主要内容整理成如下内容: 

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

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

相关文章

英语学习工具推荐

无论您是初学者还是想要巩固英语能力的学习者&#xff0c;我们都为您提供了一个高效而便捷的英语学习工具。 英语复读机&#xff0c;您可以随时输入您想要复读的英语单词、句子或者文章。我们的复读机会循环播放您输入的内容&#xff0c;帮助您加深记忆、提高听力和口语表达能力…

网络安全—小白学习笔记

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高&#xff1b; 二、则是发展相对成熟入…

【数据结构】:二叉树与堆排序的实现

1.树概念及结构(了解) 1.1树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的有一个特殊的结点&#…

数据结构之队列

目录 队列的定义与结构 队列的实现 队列的结构 初始化空队列 销毁队列 队尾入队列 队头出队列 获取队列头部元素 获取队列尾部元素 判断队列是否为空 获取队列长度 栈与队列经典试题 队列实现栈 栈实现队列 队列的定义与结构 队列是一种先进先出&#xff08;First…

Netty源码编译

Netty源码编译 想了解Netty源码&#xff0c;最好先从 netty-example 开始&#xff0c;多跑几个 example&#xff0c;了解Netty的实际应用。 编译 netty-example 会出现很多乱七八糟的问题&#xff0c;根本原因是因为缺少 io.netty.util.collection 包。 解决方法 1.先 instal…

指针(2)

1.数组名的理解 一般数组名就是数组首元素的地址 但是有2个例外&#xff1a;1.sizeof&#xff08;数组名&#xff09; 这里面数组名表示的是整个数组&#xff0c;计算整个数组的大小&#xff0c;单位为字节。 …

简单易用,效果卓越的电子期刊制作网站

在日常工作和生活中&#xff0c;我们常常需要制作各种文档和资料&#xff0c;比如电子期刊、宣传册、产品手册等。但有时候&#xff0c;我们会因为排版、设计、编辑等问题而感到烦恼。这时候&#xff0c;一个简单易用、效果卓越的电子期刊制作网站就成为了我们的得力助手&#…

相似性搜索:第 1 部分- kNN 和倒置文件索引

图片来源&#xff1a;维亚切斯拉夫叶菲莫夫 一、说明 SImilarity 搜索是一个问题&#xff0c;给定一个查询的目标是在所有数据库文档中找到与其最相似的文档。 在数据科学中&#xff0c;相似性搜索经常出现在NLP领域&#xff0c;搜索引擎或推荐系统中&#xff0c;其中需要检索最…

目标文件格式

目标文件里有什么 目标文件格式 目标文件就是源代码编译后但未进行链接的中间文件&#xff08;linux下的.o&#xff09;。 ELF文件&#xff1a;从广义上看&#xff0c;目标文件与可执行文件的格式其实几乎是一样的&#xff0c;可以将目标文件与可执行文件看成是一种类型的文…

忘记开机密码啦!我教你用ventoy找回密码

文章目录 一、前言二、实战过程三、动态演示四、原理解析五、总结 一、前言 当你有一天突然忘记了开机密码怎么办&#xff1f;又要上电脑店花个几十块让人弄&#xff1f;在上一章《你该自己学学安装操作系统了&#xff0c;小白一学就会&#xff08;ventoy装系统超详细&#xff…

Unity设计模式——建造者模式

Product类——产品类&#xff0c;由多个部件组成。 class Product {IList<string> parts new List<string>();//添加产品部件public void Add(string part){parts.Add(part);}public void Show(){foreach (string part in parts){Debug.Log("产品:"pa…

python+深度学习+opencv实现植物识别算法系统 计算机竞赛

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的植物识别算法研究与实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;4分工作量&#xff1a;4分创新点&#xff1a;4分 &#x1f9ff; 更多…

Android+Appium自动化测试环境搭建及实操

1、Appium简介1.1 Appium概念1.2 Appium工作原理 2、Appium Server环境搭建2.1 Java JDK2.1.1 下载JDK2.1.2 运行exe安装JDK&#xff0c;设置安装路径2.1.3 设置环境变量2.1.4 验证安装结果 2.2 Android SDK2.2.1 下载安装Android SDK安装包2.2.2 下载platform-tools&#xff0…

Linux下将驱动编译进内核

在开发的过程中&#xff0c;一般都是将驱动编译成模块&#xff0c;然后将其发送到开发板加载驱动进行功能验证&#xff0c;驱动的功能验证没有问题后就可以将其编译进内核了。本文将介绍如何把上一篇文章Linux下设备树、pinctrl和gpio子系统、LED灯驱动实验中的LED驱动编译到内…

【LeetCode】9. 回文数

1 问题 给你一个整数 x &#xff0c;如果 x 是一个回文整数&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 回文数是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。 例如&#xff0c;121 是回文&…

【计算机网络】IP协议详解

文章目录 一、引入 二、简单认识IP协议 2、1 IP协议基本概念 2、2 IP协议报文格式 2、3 分片与组装 2、3、1 MTU 与 MSS 2、4 网段划分 2、4、1 简单理解路由 2、4、2 IP地址 2、4、3 IP地址的划分 2、4、4 CIDR&#xff08;无类别域间路由&#xff09; 2、4、5 特殊的IP地址 …

Redis微服务架构

Redis微服务架构 缓存设计 缓存穿透 缓存穿透是指查询一个根本不存在的数据&#xff0c;缓存层和存储层都不会命中&#xff0c;通常出于容错的考虑&#xff0c;如果从存储层查不到数据则不写入缓层。 缓存穿透将导致不存在的数据每次请求都要到存储层去查询&#xff0c;失去…

【Nginx32】Nginx学习:随机索引、真实IP处理与来源处理模块

Nginx学习&#xff1a;随机索引、真实IP处理与来源处理模块 完成了代理这个大模块的学习&#xff0c;我们继续其它 Nginx 中 HTTP 相关的模块学习。今天的内容都比较简单&#xff0c;不过最后的来源处理非常有用&#xff0c;可以帮我们解决外链问题。另外两个其实大家了解一下就…

Java IO流

IO 即 Input / Output &#xff0c;输入输出流。IO流在Java中分为输入流和输出流&#xff0c;而根据数据的处理方式又分为字节流和字符流。 Java IO 流的 40 多个类都是从如下 4 个 抽象类基类中派生出来的。 InputStream /Reader : 所有的输入流的基类&#xff0c;前者是字节…

大数据flink篇之三-flink运行环境安装(一)单机Standalone安装

一、安装包下载地址 https://archive.apache.org/dist/flink/flink-1.15.0/ 二、安装配置流程 前提基础&#xff1a;Centos环境&#xff08;建议7以上&#xff09; 安装命令&#xff1a; 解压&#xff1a;tar -zxvf flink-xxxx.tar.gz 修改配置conf/flink-conf.yaml&#xff1…