PYTHON用[邻接列表]及[邻接矩阵]来存储无向图

# 图可以根据边的性质进行分类:
# 有向图(Directed Graph):在有向图中,边是有方向性的,从一个节点指向另一个节点。这意味着从节点 A 到节点 B 的边与从节点 B 到节点 A 的边可以是不同的,或者根本不存在。有向图通常用于表示具有方向性的关系,例如网页链接、社交关系中的关注关系等。
# 无向图(Undirected Graph):在无向图中,边是没有方向性的,即连接两个节点的边没有箭头指示方向。这意味着节点 A 与节点 B 之间的关系是对称的,从 A 到 B 的边与从 B 到 A 的边是相同的。无向图通常用于表示无方向性的关系,例如交通网络、好友关系等。
# 权重图(Weighted Graph):在权重图中,每条边都有一个与之关联的权重或值。这些权重可以表示连接两个节点的成本、距离、容量等信息。权重图通常用于模拟具有不同代价或度量的关系,例如路线规划中的道路长度、社交网络中的强度等。
# 无权图(Unweighted Graph):与权重图相反,无权图中的边没有相关的权重信息。它们只表示节点之间的连接关系,而不考虑连接的强度或成本。
# 这些不同类型的图可以根据问题的需求进行选择和应用,以更好地描述和解决特定领域的问题。

-------

当我们考虑一个简单的社交网络,其中有几个人以及它们之间的友谊关系时,我们可以使用无向图来表示这种关系。

假设我们有以下人物:

- Alice
- Bob
- Charlie
- David

他们之间的友谊关系如下:

- Alice 和 Bob 是朋友。
- Bob 和 Charlie 是朋友。
- Charlie 和 David 是朋友。

用无向图表示这个社交网络,节点代表人,边代表友谊关系。

这个无向图可以用以下方式表示:

节点集合 V = {Alice, Bob, Charlie, David}

边集合 E = {{Alice, Bob}, {Bob, Charlie}, {Charlie, David}}

这里的每一对节点都表示一个边,例如 {Alice, Bob} 表示 Alice 和 Bob 之间存在一条友谊边,而 {Bob, Charlie} 表示 Bob 和 Charlie 之间也存在一条友谊边。这些边都是无向的,因此没有方向性。

class UndirectedGraph:def __init__(self):self.adjacency_list = {}def add_vertex(self, vertex):if vertex not in self.adjacency_list:self.adjacency_list[vertex] = []def add_edge(self, vertex1, vertex2):if vertex1 in self.adjacency_list and vertex2 in self.adjacency_list:self.adjacency_list[vertex1].append(vertex2)self.adjacency_list[vertex2].append(vertex1)  # 更新顶点 vertex2 的邻接列表else:print("One or both vertices do not exist.")# 在你提供的代码中,add_edge() 方法用于向图中添加一条边。让我解释一下这段代码的作用:
# if vertex1 in self.adjacency_list and vertex2 in self.adjacency_list::这个条件检查 vertex1 和 vertex2 是否都存在于图的顶点列表中。只有当两个顶点都存在时,才执行接下来的操作。
# self.adjacency_list[vertex1].append(vertex2):这一行将 vertex2 添加到 vertex1 的邻接列表中,表示顶点 vertex1 与顶点 vertex2 之间有一条边。
# self.adjacency_list[vertex2].append(vertex1):这一行实际上是为了保证无向图的连通性,将 vertex1 添加到 vertex2 的邻接列表中,表示顶点 vertex2 与顶点 vertex1 之间也有一条边。这样做是因为无向图的边是双向的,如果有从 vertex1 到 vertex2 的边,也就意味着有从 vertex2 到 vertex1 的边。
# 通过这种方式,add_edge() 方法确保了图是无向图,即添加边的操作同时更新了两个顶点的邻接列表,使得图中的边是双向的。def display_graph(self):print("Adjacency List:")for vertex, neighbors in self.adjacency_list.items():print(f"{vertex}: {neighbors}")print("\nGraph:")for vertex in self.adjacency_list:print(vertex, end=" -> ")print(" -> ".join(self.adjacency_list[vertex]))# 这段代码是用来打印图的边的。让我解释一下:
# for vertex in self.adjacency_list::这个循环遍历图中的每个顶点,vertex 变量在每次迭代中都代表一个顶点名称。
# print(vertex, end=" -> "):这一行打印当前顶点的名称,然后用箭头符号 "->" 结束输出,使得下一个顶点的名称在同一行显示。
# print(" -> ".join(self.adjacency_list[vertex])):这一行使用 join() 方法将当前顶点的邻接列表连接成一个字符串,并使用箭头符号 "->" 将它们分隔开。然后,将连接后的字符串打印出来,显示当前顶点与其相邻顶点之间的连接关系。
# 所以,这段代码实际上是在打印图的邻接表,以边的形式显示图的结构。
# string.join(iterable)是一个字符串方法,用于将可迭代对象中的元素连接成一个字符串;
# string 是用来连接元素的字符串,而 iterable 则是要连接的可迭代对象,通常是列表或元组# 创建一个无向图对象
graph = UndirectedGraph()# 添加顶点
graph.add_vertex("Alice")
graph.add_vertex("Bob")
graph.add_vertex("Charlie")
graph.add_vertex("David")# 添加边 /输出的顺序与添加边的顺序有关。
graph.add_edge("Alice", "Bob")
graph.add_edge("Bob", "Charlie")
graph.add_edge("Charlie", "David")# 显示图
graph.display_graph()# 图可以根据边的性质进行分类:
# 有向图(Directed Graph):在有向图中,边是有方向性的,从一个节点指向另一个节点。这意味着从节点 A 到节点 B 的边与从节点 B 到节点 A 的边可以是不同的,或者根本不存在。有向图通常用于表示具有方向性的关系,例如网页链接、社交关系中的关注关系等。
# 无向图(Undirected Graph):在无向图中,边是没有方向性的,即连接两个节点的边没有箭头指示方向。这意味着节点 A 与节点 B 之间的关系是对称的,从 A 到 B 的边与从 B 到 A 的边是相同的。无向图通常用于表示无方向性的关系,例如交通网络、好友关系等。
# 权重图(Weighted Graph):在权重图中,每条边都有一个与之关联的权重或值。这些权重可以表示连接两个节点的成本、距离、容量等信息。权重图通常用于模拟具有不同代价或度量的关系,例如路线规划中的道路长度、社交网络中的强度等。
# 无权图(Unweighted Graph):与权重图相反,无权图中的边没有相关的权重信息。它们只表示节点之间的连接关系,而不考虑连接的强度或成本。
# 这些不同类型的图可以根据问题的需求进行选择和应用,以更好地描述和解决特定领域的问题。

Adjacency List:
Alice: ['Bob']
Bob: ['Alice', 'Charlie']
Charlie: ['Bob', 'David']
David: ['Charlie']

Graph:
Alice -> Bob
Bob -> Alice -> Charlie
Charlie -> Bob -> David
David -> Charlie
[Finished in 603ms]

无向图可以使用多种方式来进行存储,其中两种最常见的方式是邻接列表和邻接矩阵。

1. **邻接列表(Adjacency List)**:
   邻接列表是一种将图中每个节点的邻居节点列表存储起来的方式。对于每个节点,将其邻居节点以列表、链表或其他数据结构的形式存储在该节点的条目中。这种方式可以有效地节省空间,尤其适用于稀疏图,即节点之间的边相对较少的情况。Python 中可以使用字典或哈希表来实现邻接列表。

2. **邻接矩阵(Adjacency Matrix)**:
   邻接矩阵是一个二维数组,其中行和列分别代表图中的节点,矩阵的元素表示节点之间是否存在边。如果节点 i 和节点 j 之间存在边,则矩阵的第 i 行和第 j 列的元素为 1;否则为 0。这种方式相对于邻接列表来说更加直观,但是在图比较稀疏的情况下会浪费大量的空间。

在前面的代码示例中,我使用了邻接列表来存储无向图。每个节点都有一个列表,其中存储了与该节点相邻的其他节点。

----------

邻接矩阵是一种常见的图的表示方法,尤其适用于稠密图,因为它提供了直观的方式来表示节点之间的连接关系。下面是如何使用邻接矩阵来表示你提供的社交网络:

在这个邻接矩阵中,每一行和每一列分别代表一个节点,而矩阵中的值表示节点之间是否存在边。例如,第一行表示 Alice 与其他节点的连接关系,其中 1 表示 Alice 与 Bob 相连,而其他值为 0 表示 Alice 与 Charlie 和 David 不相连。

这种表示方式虽然直观易懂,但在图比较稀疏的情况下会占用大量的空间,因为矩阵的大小与节点数量的平方成正比。相对而言,邻接列表在这种情况下可能更为高效,因为它只需要存储实际存在的边。

class SocialNetwork:def __init__(self, num_nodes):self.num_nodes = num_nodesself.adj_matrix = [[0] * num_nodes for _ in range(num_nodes)]
# 这段代码在 SocialNetwork 类的构造函数中初始化了社交网络的属性:
# self.num_nodes = num_nodes: 这一行将社交网络的节点数量设置为传入的参数 num_nodes。这样,我们就可以知道社交网络有多少个节点。
# self.adj_matrix = [[0] * num_nodes for _ in range(num_nodes)]: 这一行创建了一个大小为 num_nodes × num_nodes 的二维列表(即矩阵),并将其用于表示社交网络的邻接矩阵。初始时,所有的边都被设置为 0,表示没有边相连。
# 通过这两行代码,我们在创建 SocialNetwork 对象时就初始化了社交网络的基本结构,为后续添加边和展示邻接矩阵做好了准备。def add_edge(self, node1, node2):if node1 < self.num_nodes and node2 < self.num_nodes:self.adj_matrix[node1][node2] = 1self.adj_matrix[node2][node1] = 1else:print("Invalid node index.")# 这段代码是用来在邻接矩阵中添加边的方法。让我解释一下它的工作原理:
# 首先,检查给定的节点索引 node1 和 node2 是否有效,即它们是否在社交网络的节点范围内。
# 如果节点索引有效,则将邻接矩阵中索引为 (node1, node2) 和 (node2, node1) 的位置的值设为 1,表示节点 node1 和 node2 之间存在一条边。
# 这里之所以要同时设置 (node1, node2) 和 (node2, node1) 的值是因为这是一个无向图,边不区分方向,所以节点 node1 和 node2 之间的连接关系是相互的。
# 这样,当我们调用add_edge(0, 1)时,会将邻接矩阵中的 (0, 1) 和 (1, 0) 的位置的值都设为 1,表示 Alice 和 Bob 之间存在一条边。def display_adj_matrix(self):for row in self.adj_matrix:print(" ".join(map(str, row)))# 创建一个包含4个节点的社交网络
social_network = SocialNetwork(4)# 添加边
social_network.add_edge(0, 1)  # Alice 和 Bob 是朋友
social_network.add_edge(1, 2)  # Bob 和 Charlie 是朋友
social_network.add_edge(2, 3)  # Charlie 和 David 是朋友# 显示邻接矩阵
print("邻接矩阵表示的社交网络:")
social_network.display_adj_matrix()# [[0] * num_nodes for _ in range(num_nodes)]
# 这行代码是一个列表推导式,用于创建一个二维列表(矩阵),其维度为 num_nodes × num_nodes。让我解释一下它的工作原理:# [[0] * num_nodes for _ in range(num_nodes)]: 这一整个表达式是一个嵌套的列表推导式。外层的 for _ in range(num_nodes) 循环了 num_nodes 次,每次都会生成一个包含 num_nodes 个 0 的列表。这样就生成了一个 num_nodes × num_nodes 的二维列表,其中每个元素都是 0。# 总的来说,这段代码的作用是创建一个大小为 num_nodes × num_nodes 的二维列表,并将其初始化为全 0,用于表示社交网络的邻接矩阵。

 邻接矩阵表示的社交网络:
0 1 0 0
1 0 1 0
0 1 0 1
0 0 1 0
[Finished in 563ms]

 

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

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

相关文章

parallels desktop19出来了吗?2024最新版本有哪些新功能

Parallels Desktop 19已经发布。以下是关于Parallels Desktop 19的相关信息&#xff1a; 发布时间&#xff1a;Parallels Desktop 19是在近期发布的一款虚拟机软件&#xff0c;具体发布时间为2023年下半年。 功能特点&#xff1a; 针对搭载苹果芯片的Mac进行了优化&#xff0c…

微信小程序webview和小程序通讯

1.背景介绍 1.1需要在小程序嵌入vr页面&#xff0c;同时在vr页面添加操作按钮与小程序进行通信交互 1.2 开发工具&#xff1a;uniapp开发小程序 1.3原型图 功能&#xff1a;.点击体验官带看跳转小程序的体验官带看页面 功能&#xff1a;点击立即咨询唤起小程序弹窗打电话 2.…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之五 简单进行车牌检测和识别

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之五 简单进行车牌检测和识别 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之五 简单进行车牌检测和识别 一、简单介绍 二、简单进行车牌检测和识别实现原理 …

Jmeter之Beanshell详解

一、 Beanshell概念 Beanshell: BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法;BeanShell是一种松散类型的脚本语言(这点和JS类似);BeanShell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,具有对象脚本语言特性…

[Algorithm][前缀和][模板 一维前缀和][模板 二维前缀和][寻找数组中心下标][除自身以外数组的乘积] + 前缀和原理 + 前缀和模板

目录 0.原理讲解1.[模板]一维前缀和1.题目链接2.模板代码实现 2.[模板]二维前缀和1.题目链接2.算法原理讲解3.模板代码实现 3.寻找数组的中心下标1.题目链接2.算法原理详解3.代码实现 4.除自身以外数组的乘积1.题目链接2.算法原理详解3.代码实现 0.原理讲解 前缀和&#xff1a;…

Esp8266 - USB开关分享(开源)

文章目录 简介推广自己gitee项目地址:嘉立创项目地址&#xff1a;联系我们 功能演示视频原理图嘉立创PCB开源地址原理图PCB预览 固件烧录代码编译烧录1. 软件和驱动安装2. 代码编译1. 安装所需要的依赖库文件2. 下载源代码3. 烧录代码 使用说明1. 设备配网2. 打开设备操作页面3…

【深度学习】YOLOv5,烟雾和火焰,目标检测,防火检测,森林火焰检测

文章目录 数据收集和数据标注查看标注好的数据的脚本下载yolov5创建 dataset.yaml训练参数开始训练yolov5n训练训练后的权重下载gradio部署 数据收集和数据标注 搜集数据集2w张。 pip install labelme labelme 然后标注矩形框和类别。 下载数据请看这里&#xff1a; https:…

【SpringCloud】Consul-服务注册中心及配置中心快速入门

【SpringCloud】Consul-服务注册中心及配置中心快速入门 文章目录 【SpringCloud】Consul-服务注册中心及配置中心快速入门1. 下载安装及启动2. 服务注册2.1 引入依赖2.2 yml配置2.3 启动类配置2.4 测试 3. 服务配置3.1 引入依赖3.2 yml配置3.3 创建配置文件3.4 动态刷新配置3.…

2024深圳杯(东三省)数学建模挑战赛D题:音板的振动模态分析与参数识别思路代码成品论文分析

​ 更新完整代码和成品完整论文 《2024深圳杯&东三省数学建模思路代码成品论文》↓↓↓ https://www.yuque.com/u42168770/qv6z0d/zx70edxvbv7rheu7?singleDoc# 问题重述 深圳杯&#xff08;东三省&#xff09;数学建模挑战赛2024D题&#xff1a;音板的振动模态分析与…

Docker常用命令(镜像、容器、网络)

一、镜像 1.1 存出镜像 将镜像保存成为本地文件 格式&#xff1a;docker save -o 存储文件名 存储的镜像docker save -o nginx nginx:latest 1.2 载入镜像 将镜像文件导入到镜像库中 格式&#xff1a;docker load < 存出的文件或docker load -i 存出的文件…

WordPress自动采集发布AutoPostPro汉化版插件

WP-AutoPostPro 是一款极为出色的WordPress自动采集发布插件&#xff0c;其显著优势在于能够从任何网站抓取内容并自动将其发布到你的WordPress网站上。它实现了对任何网页内容的自动采集和发布&#xff0c;整个采集过程完全自动化&#xff0c;无需手动操作。 项 目 地 址 &…

Docker学习(二十五)构建 Arthas 基础镜像

目录 一、简介二、构建基础镜像2.1 下载 Arthas2.2 编写 Dockerfile2.3 构建镜像2.4 创建容器2.5 测试 一、简介 Arthas 是一款由 阿里巴巴 开发的 线上监控诊断工具。通过全局视角实时查看应用负载、内存、GC、线程等信息&#xff0c;能在不修改代码的情况下&#xff0c;对业…

【结构型模型】享元模式

一、享元模式概述 享元模式定义&#xff1a;又叫蝇量模式&#xff0c;运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象&#xff0c;而这些对象都很相似&#xff0c;状态变化很小&#xff0c;可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细…

Microsoft SPY++ 使用教程及实操

Spy介绍 Spy (SPYXX.EXE) 是一个基于 Win32 的实用工具&#xff0c;提供系统进程、线程、窗口和窗口消息的图形视图。 Spy 有两个版本 第一个版本&#xff0c;名为 Spy (spyxx.exe)&#xff0c;用于显示发送到在 32 位进程中运行的窗口的消息。 例如&#xff0c;在 32 位进程…

立即刷新导致请求的response没有来得及加载造成的this request has no response data available

1、前端递归调用后端接口 const startProgress () > {timer.value setInterval(() > {if (progress.value < 100) {time.value--;progress.value Math.ceil(100 / wait_time.value);} else {clearInterval(timer.value);progress.value 0;timer.value null;time.…

设计模式-00 设计模式简介之几大原则

设计模式-00 设计模式简介之几大原则 本专栏主要分析自己学习设计模式相关的浅解&#xff0c;并运用modern cpp 来是实现&#xff0c;描述相关设计模式。 通过编写代码&#xff0c;深入理解设计模式精髓&#xff0c;并且很好的帮助自己掌握设计模式&#xff0c;顺便巩固自己的c…

【UE5.1 C++】VS2022下载安装

目录 步骤 一、Visual Studio下载安装 二、Visual Studio Integration Tool插件安装 先看一下UE和VS的兼容性 &#xff08;虚幻5&#xff1a;为虚幻引擎C项目设置Visual Studio开发环境&#xff09; &#xff08;虚幻4&#xff1a;设置虚幻引擎的Visual Studio&#xff0…

Cloudera最新认证体系-2024Hadoop认证

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

Golang基础3-函数、nil相关

函数 需要声明原型支持不定参数 func sum(numbers ...int)int支持返回多值支持递归支持命名返回参数 // 命名返回参数 func add(a, b int) (sum int) {sum a breturn // 这里不需要显式地写出返回值&#xff0c;因为已经在函数签名中声明了命名返回参数 } 支持匿名函数、闭包…

【刷题】前缀和入门

送给大家一句话&#xff1a; 既然已经做出了选择&#xff0c;最好还是先假定自己是对的。焦虑未来和后悔过去&#xff0c;只经历一个就够了。 – 张寒寺 《不正常人类症候群》 ☆ミヾ(∇≦((ヾ(≧∇≦)〃))≧∇)ノ彡☆ ☆ミヾ(∇≦((ヾ(≧∇≦)〃))≧∇)ノ彡☆ ☆ミヾ(∇≦((ヾ…