Hello 算法9:图

news2025/1/18 20:18:39

https://www.hello-algo.com/chapter_graph/graph/#911

图的基本概念

  • 图由顶点和边组成,比起链表(线性数据结构)和树(分治结构),图更自由也更复杂

方向性

  • 在无向图中,边表示两个顶点之间的双向连接关系,比如微信好友
  • 在有向图中,边具有方向性,比如社交网络上的关注和被关注

连通性:连通图connected graph 和 非连通图disconnected graph

  • 连通图中,从某个顶点出发,可以到达任意顶点
  • 非连通图中,从某个顶点出发,至少有一个顶点无法到达

有权图:为边增加权重,就得到了有权图weighted graph。例如游戏中计算共同游戏时间的亲密度

其他常用术语:

  • 「邻接 adjacency」:当两顶点之间存在边相连时,称这两顶点“邻接”。
  • 「路径 path」:从顶点 A 到顶点 B 经过的边构成的序列被称为从 A 到 B 的“路径”。
  • 「度 degree」:一个顶点拥有的边数。对于有向图,「入度 in-degree」表示有多少条边指向该顶点,「出度 out-degree」表示有多少条边从该顶点指出。

图的表示

1.邻接矩阵表示:以下是一个无向图的邻接矩阵表示例子

在这里插入图片描述

它有如下特点:

  • 顶点不能和自身相连,所以对角线元素无意义
  • 无向图的两个方向等价,所以矩阵关于对角线对称
  • 将1替代为权重,即可表示有权图

时间复杂度O(1),空间复杂度O(n^2)

2.邻接表

「邻接表 adjacency list」使用n个链表来表示图,链表节点表示顶点。第i个链表对应顶点i,其中存储了该顶点的所有邻接顶点(与该顶点相连的顶点)

在这里插入图片描述

边的数量显然少于n^2,所以邻接表比起矩阵,空间占用较小;但查找效率不如矩阵。

图的常见应用

顶点图计算问题
社交网络用户好友关系潜在好友推荐
地铁站点站点间连通性最短路径问题
太阳系星体万有引力作用轨道计算

图的基础操作

图的操作分为对顶点和边的操作,邻接矩阵和邻接表的实现各有不同。

基于邻接矩阵的实现

class GraphAdjMat:
    """基于邻接矩阵实现的无向图类"""
    def __init__(self, vertices: list[int], edges: list[list[int]]):
        """构造方法"""
        # 顶点列表,元素代表“顶点值”,索引代表“顶点索引”
        self.vertices: list[int] = []
        # 邻接矩阵,行列索引对应“顶点索引”
        self.adj_mat: list[list[int]] = []
        # 添加顶点
        for val in vertices:
            self.add_vertex(val)
        # 添加边, edges代表的是顶点的索引
        for e in edges:
            self.add_edge(e[0], e[1])

    def size(self):
        """获取顶点数量"""
        return len(self.vertices)

    def add_vertex(self, val: int):
        """添加顶点"""
        n = self.size()
        # 向顶点列表添加新值
        self.vertices.append(val)
        new_row = [0] * n
        # 邻接矩阵中添加新行
        self.adj_mat.append(new_row)
        # 邻接矩阵中添加新列
        for row in self.adj_mat:
            row.append(0)

    def remove_vertex(self, index: int):
        """删除顶点"""
        if index > self.size():
            raise IndexError()
        self.vertices.pop(index)
        # 在邻接矩阵中删除索引行
        self.adj_mat.pop(index)
        # 在临界矩阵中删除索引列
        for row in self.adj_mat:
            row.pop(index)

    def add_edge(self, i: int, j: int):
        """添加边"""
        if i < 0 or j < 0 or j > self.size() or i > self.size():
            raise IndexError()
        # 参数i,j对应顶点索引
        self.adj_mat[i][j] = 1
        self.adj_mat[j][i] = 1

    def remove_edge(self, i: int, j: int):
        """删除边"""
        if i < 0 or j < 0 or j > self.size() or i > self.size():
            raise IndexError()
        self.adj_mat[i][j] = 0
        self.adj_mat[j][i] = 0

    def print(self):
        """打印邻接矩阵"""
        print("顶点:", self.vertices)
        print("邻接矩阵:")
        for row in self.adj_mat:
            print(row)

基于邻接表的实现

略。https://github.com/h-kayotin/hanayo_homework/blob/master/Hello_算法/图/02_图_邻接表.py

图的遍历

图的遍历可以看做是树的一种特殊情况

广度优先遍历

由近及远,由某个顶点出发,始终优先访问最近的顶点,然后一层层向外扩张。

通常借助队列来实现

def graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> list[Vertex]:
    """广度优先遍历"""
    # 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
    # 顶点遍历序列
    res = []
    # 记录已经访问过的顶点
    visited = set[Vertex]([start_vet])
    # 队列用于实现dfs
    que = deque[Vertex]([start_vet])
    # 循环访问
    while len(que):
        vet = que.popleft()
        res.append(vet)
        # 遍历所有相邻顶点
        for adj_vet in graph.adj_list[vet]:
            # 跳过已访问的顶点
            if adj_vet in visited:
                continue
            # 入队未访问过的顶点
            que.append(adj_vet)
            visited.add(adj_vet)
    return res

广度优先的遍历序列不是唯一的

深度优先遍历

从某一点出发,优先走到底,无路可走再回头。

通常借助递归实现

def dfs(graph: GraphAdjList, visited: set[Vertex], res: list[Vertex], vet: Vertex):
    """深度优先遍历辅助函数"""
    res.append(vet)  # 记录访问顶点
    visited.add(vet)  # 标记该顶点已被访问
    # 遍历该顶点所有相邻顶点
    for adj_vet in graph.adj_list[vet]:
        if adj_vet in visited:
            continue
        # 递归访问相邻节点
        dfs(graph, visited, res, adj_vet)

def graph_dfs(graph: GraphAdjList, start_vet: Vertex) -> list[Vertex]:
    """深度优先遍历"""
    # 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
    # 顶点遍历序列
    res = []
    # 哈希表,用于记录已被访问过的顶点
    visited = set[Vertex]()
    dfs(graph, visited, res, start_vet)
    return res

深度遍历的序列也不是唯一的

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

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

相关文章

苹果手机怎么查找对方手机位置?2招快速定位!

在现代社会中&#xff0c;智能手机已经成为我们生活中不可或缺的一部分。然而&#xff0c;随着手机的普及&#xff0c;我们也面临着一些问题&#xff0c;比如手机丢失或被盗。 在这种情况下&#xff0c;如何快速准确地找到手机的位置就显得尤为重要。苹果手机怎么查找对方手机…

PKI:构建数字安全基石的关键技术

在数字化时代&#xff0c;网络安全已成为我们日常生活和工作的重要组成部分。为了确保数据的完整性、机密性和身份的真实性&#xff0c;公钥基础设施&#xff08;Public Key Infrastructure&#xff0c;简称PKI&#xff09;技术应运而生&#xff0c;为构建数字安全基石提供了重…

面试算法-151-矩阵置零

题目 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]] 解 class Solutio…

LangChain - 文档加载

文章目录 一、关于 检索二、文档加载器入门指南 三、CSV1、使用每个文档一行的 CSV 数据加载2、自定义 csv 解析和加载3、指定用于标识文档来源的列 四、文件目录 file_directory1、加载文件目录数据2、显示进度条 &#xff08;tqdm3、使用多线程 use_multithreading4、更改加载…

通用开发技能系列:Scrum、Kanban等敏捷管理策略

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 通用开发技能系列 文章&#xff0c;主要对编程通用技能 Scrum、Kanban等敏捷管理策略 进行学习 1.什么是敏捷开发 敏捷是一个描述软件开发方法的术语&#xff0c;它强调增量交付、团队协作、持续规划和持续学习…

如何使用生成式人工智能撰写关于新产品发布的文章?

利用生成式人工智能撰写新产品发布文章确实是一种既有创意又高效的内容生成方式。以下是如何做到这一点的指南&#xff0c;附带一些背景信息&#xff1a; • 背景&#xff1a;在撰写文章之前&#xff0c;收集有关您的新产品的信息。这包括产品的名称、类别、特点、优势、目标受…

git 常用命令和使用方法

作者简介&#xff1a; 一个平凡而乐于分享的小比特&#xff0c;中南民族大学通信工程专业研究生在读&#xff0c;研究方向无线联邦学习 擅长领域&#xff1a;驱动开发&#xff0c;嵌入式软件开发&#xff0c;BSP开发 作者主页&#xff1a;一个平凡而乐于分享的小比特的个人主页…

DJ的打碟是什么意思 FL Studio怎么制作打碟的效果

在如今的音乐文化中&#xff0c;DJ打碟已经成为一种重要的表演形式和音乐创作方式。但是&#xff0c;对于许多人来说&#xff0c;仍然会对DJ的打碟到底意味着什么存在疑惑&#xff0c;接下来给大家介绍DJ的打碟是什么意思&#xff0c;FL Studio怎么制作打碟的效果的具体内容。 …

Pentaho Data Integration(kettle)下载

Kettle已然是改了名了&#xff0c;新名字叫Pentaho Data Integration 网上常见的下载地址已经失效&#xff0c;被提示找不到Date Integration目录&#xff1a; https://sourceforge.net/projects/pentaho/files/Data%20Integration/ 点击页面上的pdf&#xff0c;下载文件后打…

基于单片机16路多路抢答器仿真系统设计

**单片机设计介绍&#xff0c;基于单片机16路多路抢答器仿真系统设计 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机16路多路抢答器仿真系统的设计概要主要涵盖硬件设计、软件编程以及功能实现等方面。以下是针对该设计的详细概…

ABAP 弹出输入框/弹出屏幕选择条件框

简单输入框 代码 DATA:TAB TYPE TABLE OF SVAL WITH HEADER LINE ,CODE TYPE C . TAB-TABNAME ZTAB_XX."表 TAB-FIELDNAME XXXX."字段 TAB-FIELDTEXT 条码扫描 ."说明 APPEND TAB. "弹出填写数据的框 CALL FUNCTION POPUP_GE…

mysql安装初始化(windows)

文章目录 一、下载二、 初始化数据库三、把mysql注册成服务 一、下载 https://downloads.mysql.com/archives/community/ 二、 初始化数据库 mysqld --initialize-insecure初始化完成后&#xff0c;可以开黑框运行数据库 mysqld --console三、把mysql注册成服务 mysqld -…

博士推荐 | 西安交通大学毕业的机械工程博士,EIT认证机械工程师

编辑 / 木子 审核 / 朝阳 伟骅英才 伟骅英才致力于以大数据、区块链、AI人工智能等前沿技术打造开放的人力资本生态&#xff0c;用科技解决职业领域问题&#xff0c;提升行业数字化服务水平&#xff0c;提供创新型的产业与人才一体化服务的人力资源解决方案和示范平台&#x…

webpack5如何关闭全屏错误

1、找到vue.config.js 2、在上面的devServer里面添加如下&#xff1a; client: {overlay: false, // 禁用全局错误提示},

灶具分析:电炉灶(电焰灶)、电磁炉和燃气灶到底哪个好?

在烹饪设备中&#xff0c;电炉灶、电磁炉和燃气灶都是常见的选择。每种设备都有其独特的特点和优势&#xff0c;因此&#xff0c;要决定哪一个更好&#xff0c;需要考虑到个人的需求、预算、烹饪习惯以及家庭环境等因素。下面&#xff0c;下面我将以华火电炉灶为例&#xff0c;…

2024年【道路运输企业主要负责人】报名考试及道路运输企业主要负责人证考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 道路运输企业主要负责人报名考试根据新道路运输企业主要负责人考试大纲要求&#xff0c;安全生产模拟考试一点通将道路运输企业主要负责人模拟考试试题进行汇编&#xff0c;组成一套道路运输企业主要负责人全真模拟考…

【御控物联】 JavaScript JSON结构转换(21):数组To对象——综合应用

文章目录 一、JSON结构转换是什么&#xff1f;二、术语解释三、案例之《JSON数组 To JSON对象》四、代码实现五、在线转换工具六、技术资料 一、JSON结构转换是什么&#xff1f; JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换&#xff0…

oracle hang分析使用

oracle hang分析测试 使用hang分析大部分原因在于产生锁资源的争用 1-2:只有hanganalyze输出&#xff0c;不dump任何进程 3&#xff1a;Level2Dump出在IN_HANG状态的进程 4&#xff1a;Level3Dump出在等待链里面的blockers(状态为LLEAF/LEAF_NW/IGN_DMP&#xff09; 5&…

船气废弃锅炉三维仿真vr交互展示降低培训门槛

火化炉是殡葬行业的核心设备&#xff0c;其操作技艺对于专业人才的培养至关重要。然而&#xff0c;传统实践教学受限于时间、场地、设备损耗等多重因素&#xff0c;难以给予学生充分的实操机会。面对这一挑战&#xff0c;我们创新推出了火化炉vr三维仿真培训软件&#xff0c;以…

C语言---浮点数在内存中的存储

前面跟大家介绍了整数在内存中的存储&#xff0c;这次再向大家介绍下浮点数在内存中的存储。 我们常见的浮点数有3.14&#xff0c;1E10 等等&#xff0c;浮点数家族包括float&#xff0c;double&#xff0c;long double类型。 浮点数的表示范围在头文件 float.h 定义。 1.浮…