(转载)漫画:为什么你需要了解数据结构中的图?

2024-06-13 01:38

本文主要是介绍(转载)漫画:为什么你需要了解数据结构中的图?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文地址:https://blog.csdn.net/csdnnews/article/details/88809812

640?wx_fmt=jpeg

 

640?wx_fmt=jpeg

 

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

 

640?wx_fmt=png

图的概念

 

究竟什么是图呢?大家先来想一想咱们常用的互联网产品。

举个栗子,大家一定都用过微信,假设你的微信朋友圈中有若干好友:张三、李四、王五、赵六、七大姑、八大姨。

 

640?wx_fmt=png

而你七大姑的微信号里,又有若干好友:你、八大姨、Jack、Rose。

640?wx_fmt=png

微信中,许许多多的用户组成了一个多对多的朋友关系网,这个关系网就是数据结构当中的图(Graph)

再举一个栗子,咱们在用百度地图的时候,常常会使用导航功能。比如你在地铁站A附近,你想去的地点在地铁站F附近,那么导航会告诉你一个最佳的地铁线路换乘方案。

640?wx_fmt=png

这许许多多地铁站所组成的交通网络,也可以认为是数据结构当中的图。

图,是一种比树更为复杂的数据结构。树的节点之间是一对多的关系,并且存在父与子的层级划分;而图的顶点(注意,这里不叫节点)之间是多对多的关系,并且所有顶点都是平等的,无所谓谁是父谁是子。

640?wx_fmt=png

 

640?wx_fmt=png

图的术语

 

下面我们来介绍一下图的基本术语:

640?wx_fmt=png

在图中,最基本的单元是顶点(vertex),相当于树中的节点。顶点之间的关联关系,被称为边(edge)

在有些图中,每一条边并不是完全等同的。比如刚才地铁线路的例子,从A站到B站的距离是3公里,从B站到C站的距离是5公里......这样就引入一个新概念:边的权重(Weight)。涉及到权重的图,被称为带权图(Weighted Graph)

还有一种图,顶点之间的关联并不是完全对称的。还拿微信来举例,你的好友列表里有我,但我的好友列表里未必有你。

640?wx_fmt=jpeg

 

640?wx_fmt=jpeg

 

640?wx_fmt=png

 

640?wx_fmt=jpeg

这样一来,顶点之间的边就有了方向的区分,这种带有方向的图被称为有向图

640?wx_fmt=png

相应的,在QQ当中,只要我把你从好友里删除,你在自己的好友列表里也就看不到我了。(貌似是这样)

因此,QQ的好友关系可以认为是一个没有方向区分的图,这种图被称为无向图

 

640?wx_fmt=png

图的表示

 

640?wx_fmt=jpeg

 

640?wx_fmt=jpeg

邻接矩阵

拥有n个顶点的图,它所包含的连接数量最多是n(n-1)个。因此,要表达各个顶点之间的关联关系,最清晰易懂的方式是使用二维数组(矩阵)。

具体如何表示呢?我们首先来看看无向图的矩阵表示:

640?wx_fmt=png

 

如图所示,顶点0和顶点1之间有边关联,那么矩阵中的元素A[0][1]与A[1][0]的值就是1;顶点1和顶点2之间没有边关联,那么矩阵中的元素A[1][2]与A[2][1]的值就是0。

 

像这样表达图中顶点关联关系的矩阵,就叫做邻接矩阵

 

需要注意的是,矩阵从左上到右下的一条对角线,其上的元素值必然是0。这样很容易想明白:任何一个顶点与它自身是没有连接的。

 

同时,无向图对应的矩阵是一个对称矩阵,V0和V1有关联,那么V1和V0也必定有关联,因此A[0][1]和A[1][0]的值一定相等。

 

那么,有向图的邻接矩阵又是什么样子呢?

 

640?wx_fmt=png

 

从图中可以看出,有向图不再是一个对称矩阵。从V0可以到达V1,从V1却未必能到达V0,因此A[0][1]和A[1][0]的值不一定相等。

 

邻接矩阵的优点是什么呢?简单直观,可以快速查到一个顶点和另一顶点之间的关联关系。

 

邻接矩阵的缺点是什么呢?占用了太多的空间。试想,如果一个图有1000个顶点,其中只有10个顶点之间有关联(这种情况叫做稀疏图),却不得不建立一个1000X1000的二维数组,实在太浪费了。

 

邻接表和逆邻接表

 

为了解决邻接矩阵占用空间的问题,人们想到了另一种图的表示方法:邻接表。

 

640?wx_fmt=png

 

在邻接表中,图的每一个顶点都是一个链表的头节点,其后连接着该顶点能够直接达到的相邻顶点。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

 

很明显,这种邻接表的存储方式,占用的空间比邻接矩阵要小得多。

 

要想查出从顶点0能否到达顶点1,该怎么做呢?很简单,我们从顶点0开始,顺着链表的头节点向后遍历,看看后继的节点中是否存在顶点1。

 

要想查出顶点0能够到达的所有相邻节点,也很简单,从顶点0向后的所有链表节点,就是顶点0能到达的相邻节点。

 

那么,要想查出有哪些节点能一步到达顶点1,又该怎么做呢?这样就麻烦一些了,我们要遍历每一个顶点所在的链表,看看链表节点中是否包含节点1,最后发现顶点0和顶点3可以到达顶点1。

 

640?wx_fmt=png

 

像这种逆向查找的麻烦,该如何解决呢?我们可以是用逆邻接表来解决。

 

640?wx_fmt=png

 

逆邻接表顾名思义,和邻接表是正好相反的。逆邻接表每一个顶点作为链表的头节点,后继节点所存储的是能够直接达到该顶点的相邻顶点。

 

这样一来,要想查出有哪些节点能一步到达顶点1就容易了,从顶点1向后的所有链表节点,就是能一步到达顶点1的节点。

 

因此,我们可以根据实际需求,选择使用邻接表还是逆邻接表。

 

640?wx_fmt=jpeg

 

640?wx_fmt=jpeg

 

十字链表

 

十字链表长什么样呢?用最直观的示意,是下面这样:

 

640?wx_fmt=png

 

如图所示,十字链表的每一个顶点,都是两个链表的根节点,其中一个链表存储着该顶点能到达的相邻顶点,另一个链表存储着能到达该顶点的相邻节点。

 

不过,上图只是一个便于理解的示意图,我们没有必要把链表的节点都重复存储两次。在优化之后的十字链表中,链表的每一个节点不再是顶点,而是一条边,里面包含起止顶点的下标。

 

十字链表节点和边的对应关系,如下图所示:

 

640?wx_fmt=png

 

因此,优化之后的十字链表,是下面这个样子:

 

640?wx_fmt=png

 

图中每一条带有蓝色箭头的链表,存储着从顶点出发的边;每一条带有橙色箭头的链表,存储着进入顶点的边。初学十字链表的时候,可能会觉得有些乱。

 

 

640?wx_fmt=png

总结

 

 

1.我们这一次介绍了图的定义和分类。根据图的边是否有方向,可分为有向图无向图。根据图的边是否有权重,可分为带权无权图。当然,也可以把两个维度结合起来描述,比如有向带权图,无向无权图等等。

 

2.图的表示方法有很多种。包括邻接矩阵、邻接表、逆邻接表、十字链表(还有一种邻接多重表,有兴趣的小伙伴可以自学下)。

640?wx_fmt=jpeg

 

640?wx_fmt=jpeg

 

640?wx_fmt=jpeg

 

这篇关于(转载)漫画:为什么你需要了解数据结构中的图?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1055933

相关文章

【数据结构】线性表:顺序表

文章目录 1. 线性表2. 顺序表2.1 概念及结构2.2 接口实现2.3 顺序表的问题及思考 1. 线性表 线性表是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串… 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式

数据结构9——排序

一、冒泡排序 冒泡排序(Bubble Sort),顾名思义,就是指越小的元素会经由交换慢慢“浮”到数列的顶端。 算法原理 从左到右,依次比较相邻的元素大小,更大的元素交换到右边;从第一组相邻元素比较到最后一组相邻元素,这一步结束最后一个元素必然是参与比较的元素中最大的元素;按照大的居右原则,重新从左到后比较,前一轮中得到的最后一个元素不参4与比较,得出新一轮的最大元素;按照上述规则,每一轮结

BD错误集锦8——在集成Spring MVC + MyBtis编写mapper文件时需要注意格式 You have an error in your SQL syntax

报错的文件 <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.yuan.dao.YuanUserDao"><!

@ControllerAdvice:你可以没用过,但是不能不了解

1.概述 最近在梳理Spring MVC相关扩展点时发现了@ControllerAdvice这个注解,用于定义全局的异常处理、数据绑定、数据预处理等功能。通过使用 @ControllerAdvice,可以将一些与控制器相关的通用逻辑提取到单独的类中进行集中管理,从而减少代码重复,提升代码的可维护性。 定义如下 /*** Specialization of {@link Component @

算法与数据结构面试宝典——回溯算法详解(C#,C++)

文章目录 1. 回溯算法的定义及应用场景2. 回溯算法的基本思想3. 递推关系式与回溯算法的建立4. 状态转移方法5. 边界条件与结束条件6. 算法的具体实现过程7. 回溯算法在C#,C++中的实际应用案例C#示例C++示例 8. 总结回溯算法的主要特点与应用价值 回溯算法是一种通过尝试各种可能的组合来找到所有解的算法。这种算法通常用于解决组合问题,如排列、组合、棋盘游

嵌入式学习——数据结构(哈希、排序)——day50

1. 查找二叉树、搜索二叉树、平衡二叉树 2. 哈希表——人的身份证——哈希函数 3. 哈希冲突、哈希矛盾 4. 哈希代码 4.1 创建哈希表 4.2  5. 算法设计 5.1 正确性 5.2 可读性(高内聚、低耦合) 5.3 健壮性 5.4 高效率(时间复杂度)时间复杂度越低,效率越高, 5.5 低储存(空间复杂度)空间复杂度越低,存储空间越少 6.排序算法 6.1 冒

【数据结构与算法 经典例题】使用队列实现栈(图文详解)

💓 博客主页:倔强的石头的CSDN主页               📝Gitee主页:倔强的石头的gitee主页    ⏩ 文章专栏:《数据结构与算法 经典例题》C语言                                   期待您的关注 ​​ 目录  一、问题描述 二、前置知识 三、解题思路 四、C语言实现代码 🍃队列实现代码:

数据结构:二叉树详解 c++信息学奥赛基础知识讲解

目录 一、二叉树的定义 二、二叉树的形态 三、二叉树的性质 四、二叉树的存储 五、二叉树的创建与遍历(递归) 六、二叉树实现 创建二叉树 展示二叉树 1、计算数的高度 2、计算数的叶子数量 3、计算数的宽度 4、层次遍历 5、前序遍历 递归写法 非递归写法 6、中序遍历 递归写法 非递归写法 7、后序遍历 递归写法 非递归写法 8、输出根节点到所有叶

Java数据结构4-链表

1. ArrayList的缺陷 由于其底层是一段连续空间,当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时间复杂度为O(n),效率比较低,因此ArrayList不适合做任意位置插入和删除比较多的场景。因此:java集合中又引入了LinkedList,即链表结构。 2. 链表 2.1 链表的概念及结构 链表是一种物理存储结构上非连续存储结构,数据元素

大学生自救数据结构与算法(py实现)——01递归

目录 目录 递归 基本概念 工作原理 基本要素 优点 缺点 实现技巧 实例解析:计算阶乘 斐波那契数列 高效的斐波那契数列 python中的最大递归深度 二分查找 基本原理 性能分析 优化与变体 线性递归  元素序列的递归求和 二路递归 二路递归的基本概念 典型应用 工作原理 多重递归  示例:计算卡特兰数(Catalan Number) 尾递