紫薇星上的数据结构(9)

我们终于来到了数据结构的最后一个逻辑结构——图形结构,大噶冲冲冲!


9.1初识图论

今天我们来整理一个新的逻辑结构——图形结构,之前学的树形结构可以看作简化版的图形结构,图(Graph)是表示物件与物件之间的关系的数学对象,是图论的基本研究对象;图是一些点和线的集合,图中的点叫做顶点(VerTex),两个顶点的连线叫做边(Edges)。

定义:图:Graph = (V, E);V:顶点(数据元素)的有穷非空集合;E:边得有穷集合。

从大的方向来讲,图分为有向图(Directed Graphs)和无向图(Undirected Graphs):

无向图:每一条边都是无方向的,使用无序偶对(Vi, Vj)表示,如果图中任意两条边都是无向边,那么这个图就是无向图。

有向图:每一条边都是有方向的,也称为弧(arc),使用有序偶对<Vi, Vj>表示,如果图中任意两条边都是有向边,那么这个图就是有向图。

还有完全图:任意两个顶点之间都有一条边相连的图就叫完全图。

若一个完全图中有 n 个顶点,那么无向完全图中一共有(n(n-1)/2)条边,有向完全图中一共有n(n-1)条边。

还有网:网是边或弧带权的图,图的边或弧具有的相关数称为权。

假设有两个图:G1 = (V1, {E1})和G2 =  (V2, {E2}),如果V2∈V1且E2∈E1,则称G2为G1的子图。

上图中左图的子图就是右边的所有图,有向图也是一样的,不过有向图的子图有向边的方向要和有向图的有向边方向一致。

图的顶点与边的关系

对于无向图G = (V, {E}):

  • 如果边(Vi, Vj)∈E,则称顶点Vi和Vj互为邻接点;
  • 边(Vi, Vj)依附于顶点Vi和Vj(或边与顶点相关联);
  • 顶点的度是和V相关联的边的数量,记为TD(V);
  • 无向图的边数为各顶点度数和的一半。

对于有向图G = (V, {E}):

  • 如果弧<Vi, Vj>∈E,则称顶点Vi和Vj互为邻接点;
  • 弧<Vi, Vj>依附于顶点Vi和Vj(或边与顶点相关联);
  • 以顶点V为头的弧的数目称为V的入度,记为ID(V);
  • 以顶点V为尾的弧的数目称为V的出度,记为OD(V);
  • 顶点V的度 TD(V) = ID(V) + OD(V);
  • 有向图的弧数 = 入度数 = 出度数;
  • 无向图的边数为各顶点度数和的一半。

关于路径:

  • 连续的边构成的有序顶点集合就叫路径;
  • 无向图 G = (V, {E})中,从顶点Vi到Vj的路径是如下的顶点的序列:{Vi, V1, V2, ... , Vj};
  • 如果是有向图,那么路径也是有向的;
  • 路径长度就是路径上边或弧的数量。

回路或环:

  • 第一个顶点到最后一个顶点相同的路径称为回路或环;
  • 序列中顶点不重复出现的路径称为简单路径;
  • 除第一个顶点和最后一个顶点之外,其余顶点都不重复的路径称为简单回路或简单环;

连通图:

  • 在图 G = (V, {E})中,若对任意两个顶点Vi到Vj都存在从Vi到Vj的路径,则称G为连通图;
  • 如果该连通图为一个有向图,那就称为强连通图;
  • 与之对应的是非连通图、非强连通图。

总结一下,图的分类:

9.2图的操作

上面这张图片中一共有四个图,但是但我们仔细时就能发现这四个图表示的完全是一个图,只是顶点的位置改变了而已,所以图的存储可以是多样的。

图的顺序存储结构

图可以使用邻接矩阵的方式存储,大概是这样子的:这样的一个矩阵中每行代表一个顶点,每列也代表一个顶点,那么在每个位置就代表对应的两个顶点是否有边相连。

图的链式存储结构

图的链式存储结构一共有三种,我们主要来说一下第一种——邻接表表示法。

因为邻接多重表和十字链表都是邻接表的变化来的,所以不再过多详细说明。

邻接矩阵实现存储结构

那么如何实现呢?如果我们选择了使用顶点存储,那么就要使用顺序表或者链表;如果选择使用边来存储,那么就使用邻接矩阵或者邻接表,邻接矩阵的实质就是一个二维数组、而邻接表的实质是多重链表。

我们使用邻接矩阵表示图的时候,矩阵中每行代表一个顶点,每列也代表一个顶点,每个位置就代表对应的两个顶点是否有边相连,如果相连就为1,不相连就为0。

这里要注意对无向图来说:

  • 无向图的邻接矩阵是对称的;
  • 顶点 i 的度 = 第 i 行(列)中的 1 的个数;
  • 完全图的邻接矩阵中,对角元素为0,其余为1。

而对于有向图来说:

  • 有向图的邻接矩阵可能不是对称的;
  • 顶点的出度 = 第 i 行的元素之和;
  • 顶点的入度 = 第 i 列的元素之和;
  • 顶点的度 = 第 i 行的元素之和 + 第 i 列的元素之和。

而对于网来说,因为有了权值的出现,所以两个顶点对应的位置上为两个顶点的有向边上的权值,而不是1或0,同时顶点到自身的位置上的权值用0表示,到达不了没有边相连的位置上的权值用∞表示。

这里我们就不演示代码了,依旧以理解原理为主,需要代码的同学可以私信我。

邻接表实现存储结构

当我们知晓了邻接矩阵后,就有一种情况不得不考虑,它的邻接矩阵是这样子的:

这样的图如果使用邻接矩阵来存储的话,建立了二维数组就可以明显看到有很多空间被浪费了,那么如何解决呢?答案是使用邻接表来存储。

邻接表是用多重链表来存储的,首先建立一个一维数组来存放所有的顶点,在第一个顶点的指针域存放它所指向的下一个顶点的数据,在下一个顶点的指针域又存放下一个顶点的数据,直到没有顶点为止;第二个顶点,第三个也是如此。

这样就可以所有的顶点保存在多重链表中了,我们举一个简单的例子:

这样子就很清楚了,因为我们使用的是无向图,所以邻接表不是唯一的,因为各个结点的链入顺序是任意的,而它的度就是单链表中的链接的结点个数。

邻接矩阵表示方法和邻接表表示方法

 9.3图的遍历

从已给的连通图中的某一顶点出发,沿着一些边访遍图中所有的顶点,且使每个顶点仅被访问一次,这就是图的遍历。图的遍历是图的基本运算,实质上就是找每个顶点的邻接点的过程。图中可能存在回路,且图的任一顶点都可能与其他顶点相通,在访问完某个顶点之后可能会沿着某些边又回到了曾经访问过的顶点。

深度优先搜索

深度优先搜索(Depyh-First-Search)就是仿照树的先序遍历,从图的第一个顶点开始然后尽可能深得去访问结点和分支,我们举个例子来说明一下:

在左边这个图中,我们从V1开始访问,因为是按照深度访问结点和分支,所以开始访问到V5都很顺利,然后V5访问过后V1的这条分支已经被访问完了,V5已经没有下一个没有访问过的邻接点了,所以要回溯到V1然后开始访问下一个分支。

简单解释一下过程:

  • 访问图中任意一起始顶点V1,由V出发,访问它的任一邻接点V2;
  • 再从V2出发,访问它的邻接但没被访问过的顶点V3;
  • 然后按上述方法继续访问,一直访问到V5,此时在这条分支上已经没有邻接但未被访问的顶点了;
  • 接着回溯一步,退回到前一步访问的顶点,寻找它的邻接但未被访问的顶点;
  • 如果没有就再次回溯,一直回溯到起始顶点;
  • 如果有就访问,直到所有的点都被访问一遍。

广度优先搜索

广度优先搜索(Breath-First-Search)是仿照树的层序遍历,从图的第一个顶点开始然后一层一层的去访问结点和分支,我们举个例子来说明一下:

这里解释一下原理:

  • 首先访问起始点V1;
  • 依次访问V1的邻接点;
  • 一次访问这些顶点中的未被访问过的邻接点;
  • 直到所有的点都被访问完为止。

这就是关于图的所有知识点了,我们今天没有讲代码所以文章看着会短一些,但都是实打实的知识点和原理,大家要认真理解,如果需要代码,可以私信我,下次我们将整理最后一部分,算法的知识点,我们下次见👋

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值