数据结构—图(Part Ⅰ)—图的存储&遍历


数据结构-图(第八章)的整理笔记,若有错误,欢迎指正。

图的基本概念

  • 图(graph)G由两个集合V(vertex)和E(edge)组成,记为G=(V,E),其中V是顶点的有限集合,记为V(G),E是连接V中两个不同顶点(顶点对)的边的有限集合,记为E(G)。
  • 可以用字母或自然数来标识图中的顶点,这里约定用(0≤i≤n-1)表示第i个顶点的编号,其中n为图中顶点的个数。当E(G)为空集时,则图G只有顶点,没有边。
  • !注意:线性表可以是空表,树可以是空树,但图不可以是空图。就是说图中不能一个顶点也没有,图的顶点集V一定是非空集,但边集E可以为空,此时图中只有顶点而没有边。

端点和邻接点

  • 在一个无向图中,若存在一条边(i,j),则称顶点i和顶点j为该边的两个端点(endpoint),并称它们互为邻接点(adjacent),即顶点i是顶点j的一个邻接点,顶点j也是顶点i的一个邻接点,边(i,j)和顶点i、j关联。关联于相同两个端点的两条或者两条以上的边称为多重边,在数据结构中讨论的图都是指没有多重边的图。
  • 在一个有向图中,若存在一条有向边<i,j>(也称为弧),则称此边是顶点i的一条出边,同时也是顶点j的一条入边,i为此边的起始端点(简称为起点),j为此边的终止端点(简称终点),顶点j是顶点i的出边邻接点,顶点i是顶点j的入边邻接点

有向图

  • 在图G中,如果表示边的顶点对(或序偶)是有序的,则称G为有向图(digraph)。在有向图中代表边的顶点对用尖括号括起来,用于表示一条有向边,如<i,j>表示从顶点i到顶点j的一条边,可见<i,j>和<j,i>是两条不同的边。
    在这里插入图片描述

无向图

  • 如果在图G中,若<i,j>∈E(G)必有<j,i>∈E(G),即E(G)是对称的,则用(i,j)代替这两个顶点对,表示顶点i与顶点j的一条无向边,则称G为无向图(undirgraph)。显然在无向图中(i,j)和(j,i)所代表的是同一条边,所以,无向图可以看成是有向图的特例。
    在这里插入图片描述

简单图、多重图

  • 如果一个图G满足:①不存在重复边;②不存在顶点到自身的边,那么称图G为简单图
  • 若图G中某两个结点之间的边数多于一条,又允许顶点通过同一条边和自己关联,则G为多重图
    在这里插入图片描述
  • 数据结构课程只探讨 “简单图”。

完全图(也称简单完全图)

  • 无向完全图(complete undirgraph)——无向图中任意两个顶点之间都存在边(若无向图的顶点数为n,则边数为 C n 2 = n ( n − 1 ) 2 ) C_n^2=\frac{n(n-1)}{2}) Cn2=2n(n1))
  • 有向完全图(complete digraph)——有向图中任意两个顶点之间都存在方向相反的两条弧(若无向图的顶点数为n,则边数为 2 C n 2 = n ( n − 1 ) 2C_n^2=n(n-1) 2Cn2=n(n1))。
    在这里插入图片描述

子图、生成子图

  • 设有两个图G=(V, E)和G’=(V’, E’),若V’是V的子集,且E’是E的子集,则称G’是G的子图(subgraph)。
  • 若有满足V(G’) = V(G)的子图G’,则称其为G的生成子图
    在这里插入图片描述

连通、连通图和连通分量

  • 无向图中,若从顶点v到顶点w有路径存在,则称v和w是连通的。
  • 若图G中任意两个顶点都是连通的,则称图G为连通图(connected graph),否则称为非连通图(unconnected graph)。
    在这里插入图片描述
  • !注意: 对于n个顶点的无向图G,若G是连通图,则最少有n-1条边;若G是非连通图,则最多可能有 C n − 1 2 C_{n-1}^2 Cn12条边。
  • 无向图中的极大连通子图(子图必须连通,且包含尽可能多的顶点和边)称为连通分量(connected component)。
    在这里插入图片描述
    !注意区分:极大连通子图和极小连通子图
  • 极大连通子图是无向图的连通分量,极大即要求该连通子图包含其所有的边;极小连通子图是既要保持图的连通又要使得边数最少的子图。
    在这里插入图片描述

强连通、强连通图、强连通分量

  • 有向图中,若从顶点v到顶点w和从顶点w到顶点v之间都有路径,则称这两个顶点是强连通的。
  • 若图中任何一对顶点都是强连通的,则称此图为强连通图(strongly connected graph)。
    在这里插入图片描述
  • !注意: 对于n个顶点的有向图G, 若G是强连通图,则最少有n条边(形成回路)。
  • 有向图中的极大强连通子图(子图必须强连通,同时保留尽可能多的边)称为有向图的强连通分量(strongly connected component)。
    在这里插入图片描述

生成树、生成森林

  • 连通图(无向图)生成树是包含图中全部顶点的一个极小连通子图(边尽可能的少,但要保持连通)。
  • 若图中顶点数为n,则它的生成树含有 n-1 条边。对生成树而言,若砍去它的一条边,则会变成非连通图,若加上一条边则会形成一个回路。
    在这里插入图片描述
  • 在非连通图(无向图)中,连通分量的生成树构成了非连通图的生成森林
    在这里插入图片描述

顶点的度、入度、出度

  • 对于无向图:顶点v的度是指依附于该顶点的边的条数,记为TD(v)。
    在具有n个顶点、e条边的无向图中, ∑ i = 1 n T D ( v i ) = 2 e \sum_{i=1}^nTD(v_i)=2e i=1nTD(vi)=2e,即无向图的全部顶点的度的和等于边数的2倍。
  • 对于有向图
    入度是以顶点v为终点的有向边的数目,记为ID(v);
    出度是以顶点v为起点的有向边的数目,记为OD(v)。
    顶点v的度等于其入度和出度之和,即TD(v) = ID(v) + OD(v)。
    在具有n个顶点、e条边的有向图中, ∑ i = 1 n I D ( v i ) = ∑ i = 1 n O D ( v i ) = e \sum_{i=1}^nID(v_i)=\sum_{i=1}^nOD(v_i)=e i=1nID(vi)=i=1nOD(vi)=e
    在这里插入图片描述

边的权和网

  • 边的权——在一个图中,每条边都可以标上具有某种含义的数值,该数值称为该边的权值。
  • 带权图/网——边上带有权值的图称为带权图,也称网。
  • 带权路径长度——当图是带权图时,一条路径上所有边的权值之和,称为该路径的带权路径长度

稠密图、稀疏图

  • 当一个图接近完全图时,称为稠密图(dense graph)。
  • 当一个图含有较少的边数时(如 e < l o g 2 n e<log_2^n e<log2n),称为稀疏图(sparse graph)。
    在这里插入图片描述

路径、路径长度和回路

  • 路径(path)——顶点 v p v_p vp到顶点 v q v_q vq之间的一条路径是指顶点序列 , v p , v i 1 , v i 2 , . . . , v i m , v q v_p,v_{i_1},v_{i_2},...,v_{i_m},v_q vp,vi1,vi2,...,vim,vq

  • 路径长度(path length)——路径上边的数目

  • 回路(cycle)——第一个顶点和最后一个顶点相同的路径称为回路或环。
    在这里插入图片描述

  • !注意:顶点之间有可能不存在路径。

  • !注意:有向图的路径也是有向的。

简单路径、简单回路

  • 简单路径——在路径序列中,顶点不重复出现的路径称为简单路径。
  • 简单回路(simple cycle)——除第一个顶点和最后一个顶点外,其余顶点不重复出现的回路称为简单回路。
    在这里插入图片描述

距离

  • 点到点的距离——从顶点u出发到顶点v的最短路径若存在,则此路径的长度称为从u到v的距离。
  • 若从u到v根本不存在路径,则记该距离为无穷(∞)。
    在这里插入图片描述

树、有向树

  • ——不存在回路,且连通的无向图。
  • 有向树——一个顶点的入度为0、其余顶点的入度均为1的有向图,称为有向树。
    在这里插入图片描述
  • !注意:n个顶点的树,必有n-1条边。n个顶点的图,若|E|>n-1,则一定有回路。

图的存储

  • 图的存储结构除了要存储图中各个顶点本身的信息以外,同时还要存储顶点与顶点之间的所有关系(边的信息)。

邻接矩阵法(adjacency matrix)

邻接矩阵存储法

邻接表法(adjacency list)

邻接表法

十字链表法(orthogonal list)

  • 十字链表是有向图的一种链式存储结构。在十字链表中,对应于有向图中的每条弧有一个点,对应于每个顶点也有一个结点。
  • 弧结点中有5个域:尾域(tailvex)和头域(headvex)分别指示尾和头这两个顶点在图中的位置:链域hlink指向弧头相同的下一条弧;链域tlink指向弧尾相同的下一条弧;info域指向该弧的相关信息。这样,弧头相同的弧就在同一个链表上,弧尾相同的弧也在同一个链表上。
  • 顶点结点中有3个域:data域存放顶点相关的数据信息,如顶点名称;firstin和firstout两个域分別指向以该顶点为弧头或弧尾的第一个弧结点。
  • !注意:顶点结点之间是顺序存储的。
  • 在十字链表中,既容易找到为尾的弧,又容易找到为头的弧,因而容易求得顶点的出度和入度。图的十字链表表示是不唯一的,但一个十字链表表示确定一个图。

邻接多重表(adjacency multi-list)

  • 邻接多重表是无向图的另一种链式存储结构
  • 在邻接表中,容易求得顶点和边的各种信息,但在邻接表中求两个顶点之间是否存在边和对边执行删除等操作时,需要分别在两个顶点的边表中遍历,效率较低。
    -
  • 其中,i和j为该边依附的两个顶点在图中的位置;iLink指向下一条依附于顶点i的边;jLink指向下一条依附于顶点j的边;info为指向和边相关的各种信息的指针域。
    每个顶点也用一个结点表示,其中,data域存储该顶点的相关信息,firstedge域指示第一条依附于该顶点的边。
  • 在邻接多重表中,所有依附于同一顶点的边串联在同一链表中,由于每条边依附于两个顶点,因此每个边结点同时链接在两个链表中。对无向图而言,其邻接多重表和邻接表的差别仅在于:同一条边在邻接表中用两个结点表示,而在邻接多重表中只有一个结点。

删除一个结点

四种存储方式的对比

邻接表邻接矩阵十字链表邻接多重表
空间复杂度无向图:O(|V|+2|E|);有向图:O(|V|+|E|)O(|V| 2 ^2 2)O(|V|+|E|)O(|V|+|E|)
适合用于存储稀疏图存储稠密图只能存有向图只能存无向图
表示方式不唯一唯一不唯一不唯一
计算度/出度/入度计算有向图的度、入度不方便、其余很方便必须遍历对应行或列很方便很方便
找相邻的边找有向图的入边不方便,其余很方便必须遍历对应行或列很方便很方便

图的基本操作

图 的 基 本 操 作 { A d j a c e n t ( G , x , y ) : 判 断 图 G 是 否 存 在 边 < x , y > 或 ( x , y ) 。 N e i g h b o r s ( G , x ) : 列 出 图 G 中 与 结 点 x 邻 接 的 边 。 I n s e r t V e r t e x ( G , x ) : 在 图 G 中 插 入 顶 点 x 。 D e l e t e V e r t e x ( G , x ) : 从 图 G 中 删 除 顶 点 x 。 A d d E d g e ( G , x , y ) : 若 无 向 边 ( x , y ) 或 有 向 边 < x , y > 不 存 在 , 则 向 图 G 中 添 加 该 边 。 R e m o v e E d g e ( G , x , y ) : 若 无 向 边 ( x , y ) 或 有 向 边 < x , y > 存 在 , 则 从 图 G 中 删 除 该 边 。 F i r s t N e i g h b o r ( G , x ) : 求 图 G 中 顶 点 x 的 第 一 个 邻 接 点 , 若 有 则 返 回 顶 点 号 。 若 x 没 有 邻 接 点 或 图 中 不 存 在 x , 则 返 回 − 1 。 N e x t N e i g h b o r ( G , x , y ) : 假 设 图 G 中 顶 点 y 是 顶 点 x 的 一 个 邻 接 点 , 返 回 除 y 外 顶 点 x 的 下 一 个 邻 接 点 的 顶 点 号 , 若 y 是 x 的 最 后 一 个 邻 接 点 , 则 返 回 − 1 。 G e t _ e d g e _ v a l u e ( G , x , y ) : 获 取 图 G 中 边 ( x , y ) 或 < x , y > 对 应 的 权 值 。 S e t _ e d g e _ v a l u e ( G , x , y , v ) : 设 置 图 G 中 边 ( x , y ) 或 < x , y > 对 应 的 权 值 为 v 。 图的基本操作\begin{cases} Adjacent(G,x,y):判断图G是否存在边<x,y>或(x,y)。 \\ Neighbors(G,x):列出图G中与结点x邻接的边。 \\ InsertVertex(G,x):在图G中插入顶点x。 \\ DeleteVertex(G,x):从图G中删除顶点x。 \\ AddEdge(G,x,y):若无向边(x,y)或有向边<x,y>不存在,则向图G中添加该边。 \\ RemoveEdge(G,x,y):若无向边(x,y)或有向边<x,y>存在,则从图G中删除该边。 \\ FirstNeighbor(G,x):求图G中顶点x的第一个邻接点,若有则返回顶点号。若x没有邻接点或图中不存在x,则返回-1。 \\ NextNeighbor(G,x,y):假设图G中顶点y是顶点x的一个邻接点,返回除y外顶点x的下一个邻接点的顶点号,若y是x的最后一个邻接点,则返回-1。 \\ Get\_edge\_ value(G,x,y):获取图G中边(x,y)或<x,y>对应的权值。 \\ Set\_edge\_value(G,x,y,v):设置图G中边(x,y)或<x,y>对应的权值为v。 \\ \end{cases} Adjacent(G,x,y)G<x,y>(x,y)Neighbors(G,x)GxInsertVertex(G,x)GxDeleteVertex(G,x)GxAddEdge(G,x,y)(x,y)<x,y>GRemoveEdge(G,x,y)(x,y)<x,y>GFirstNeighbor(G,x)Gxxx1NextNeighbor(G,x,y)Gyxyxyx1Get_edge_value(G,x,y)G(x,y)<x,y>Set_edge_value(G,x,y,v)G(x,y)<x,y>v

时间复杂度的分析

邻接矩阵邻接表
Adjacent(G,x,y)O(1)O(1)~O(|V|)
Neighbors(G,x)O(|V|)O(1)~O(|V|)
InsertVertex(G,x)O(1)O(1)
DeleteVertex(G,x)O(|V|)O(1)~O(|E|)
Addedge(G,x,y)O(1)O(1)(头插法)~O(|V|(尾插法))
RemoveEdge(G,x,y)O(1)O(1)~O(|V|)
FirstNeighbor(G,x)O(1)~O(|V|)O(1)
NextNeighbor(G,x,y)O(1)~O(|V|)O(1)
Get_edge_ value(G,x,y)O(1)O(1)~O(|V|)
Set_edge_value(G,x,y,v)O(1)O(1)~O(|V|)

其中,|V|表示图G中顶点的个数,|E|表示图G中边的条数。

图的遍历

  • 从给定图中任意指定的顶点(称为初始点)出发,按照某种搜索方法沿着图的边访问图中的所有顶点,使每个顶点仅被访问一次,这个过程称为图的遍历
  • 如果给定图是连通的无向图或者是强连通的有向图,则遍历过程一次就能完成,并可按访问的先后顺序得到由该图的所有顶点组成的一个序列。
  • 图的遍历比树的遍历更复杂,因为从树根到达树中的任意结点只有一条路径,而从图的初始点到达图中的每个顶点可能存在着多条路径。当沿着图中的一条路径访问过某一顶点之后,可能还沿着另一条路径回到该顶点,即存在回路。为了避免同一个顶点被重复访问,必须记住每个被访问过的顶点。为此,可设置一个访问标记数组visited[ ],当顶点被访问过时,数组中的元素visited[ ]置为true,否则置为false。
  • 根据搜索方法的不同,图的遍历方法有两种:一种叫深度优先遍历(Depth First Search,DFS),另ー种叫广度优先遍历(Breadth First Search,BFS)。

广度优先搜索

图的广度优先搜索

广度优先生成树

  • 在广度遍历的过程中,我们可以得到一棵遍历树,称为广度优先生成树。需要注意的是,一给定图的邻接矩阵存储表示是唯一的,故其广度优先生成树也是唯一的,但由于邻接表存储表示不唯一,故其广度优先生成树也是不唯一的。
    在这里插入图片描述

广度优先生成森林

  • 对非连通图的广度优先遍历,可得到广度优先生成森林。
    在这里插入图片描述

深度优先搜索

图的深度优先搜索

深度优先生成树

  • 与广度优先搜索一样,深度优先搜索也会产生一棵深度优先生成树。当然,这是有条件的,即对连通图调用DFS才能产生深度优先生成树,否则产生的将是深度优先生成森林。与BFS类似,基于邻接表存储的深度优先生成树是不唯一的。
    在这里插入图片描述

深度优先生成森林

在这里插入图片描述

图的遍历与图的连通性

  • 图的遍历算法可以用来判断图的连通性。
  • 对于无向图来说,若无向图是连通的,则从任一结点出发,仅需一次遍历就能够访问图中的所有顶点;若无向图是非连通的,则从某一个顶点出发,一次遍历只能访问到该顶点所在连通分量的所有顶点,而对于图中其他连通分量的顶点,则无法通过这次遍历访问。
  • 对于有向图来说,若从初始点到图中的每个顶点都有路径,则能够访问到图中的所有顶点,否则不能访问到所有顶点。
  • 故在BFSTraverse()或DFSTraverse()中添加了第二个for循环,再选取初始点,继续进行遍历,以防止一次无法遍历图的所有顶点。
  • 对于无向图,上述两个函数调用BFS(G,i)或DFS(G,i)的次数等于该图的连通分量数;而对于有向图则不是这样;因为一个连通的有向图分为强连通的和非强连通的,它的连通子图也分为强连通分量和非强连通分量,非强连通分量一次调用BFS(G,i)或DFS(G,i)无法访问到该连通分量的所有顶点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值