python数据结构与算法分析(四)

本文深入探讨了图的数据结构,包括顶点、边和权重的概念,并介绍了图的抽象数据类型,如广度优先搜索、深度优先搜索、拓扑排序、强连通单元和最短路径问题。通过Python实现,解释了邻接矩阵和邻接表两种图的表示方式,以及它们在稀疏图中的效率差异。文章还详细分析了广度优先搜索和深度优先搜索的算法流程,以及它们在解决实际问题,如单词转换、骑士周游和最短路径问题中的应用。最后,讨论了拓扑排序和强连通单元的概念,以及Dijkstra算法和Prim算法在构建最小生成树中的作用,为理解图论和算法提供了丰富的实例。
摘要由CSDN通过智能技术生成

数据结构与算法分析(一)
数据结构与算法分析(二)
数据结构与算法分析(三)

与树相比,图是更通用的结构;事实上,可以把树看作一种特殊的图。
顶点
顶点又称节点,是图的基础部分。它可以有自己的名字,我们称作“键”。顶点也可以带有附加信息,我们称作“有效载荷”。

边是图的另一个基础部分。两个顶点通过一条边相连,表示它们之间存在关系。边既可以是单向的,也可以是双向的。如果图中的所有边都是单向的,我们称之为有向图。
权重
边可以带权重,用来表示从一个顶点到另一个顶点的成本。例如在路线图中,从一个城市到另一个城市,边的权重可以表示两个城市之间的距离。
有了上述定义之后,就可以正式地定义图。图可以用G来表示,并且G = (V, E)。其中,V是一个顶点集合,E是一个边集合。每一条边是一个二元组(v, w),其中w, v∈V。可以向边的二元组中再添加一个元素,用于表示权重。子图s是一个由边e和顶点v构成的集合,其中e⊂E且v⊂V。
下图展示了一个简单的带权有向图。我们可以用6个顶点和9条边的两个集合来正式地描述这个图。
在这里插入图片描述
在这里插入图片描述
上图中的例子还体现了其他两个重要的概念。
路径
路径是由边连接的顶点组成的序列。路径的正式定义为w1, w2,···, wn,其中对于所有的1≤i≤n-1,有(wi, wi+1)∈E。无权重路径的长度是路径上的边数,有权重路径的长度是路径上的边的权重之和。以上图为例,从 V3到 V1的路径是顶点序列(V 3, V 4,V 0, V1),相应的边是{(v3, v4,7), (v4, v0,1), (v0, v1,5)}。

环是有向图中的一条起点和终点为同一个顶点的路径。例如,上图中的路径(V5, V2, V3, V5)就是一个环。没有环的图被称为无环图,没有环的有向图被称为有向无环图,简称为DAG。接下来会看到,DAG能帮助解决很多重要的问题。

图的抽象数据类型

图的抽象数据类型由下列方法定义。
Graph()新建一个空图。
addVertex(vert)向图中添加一个顶点实例。
addEdge(fromVert, toVert)向图中添加一条有向边,用于连接顶点fromVert和toVert。
addEdge(fromVert, toVert, weight)向图中添加一条带权重weight的有向边,用于连接顶点fromVert和toVert。
getVertex(vertKey)在图中找到名为vertKey的顶点。
getVertices()以列表形式返回图中所有顶点。
in通过vertex in graph这样的语句,在顶点存在时返回True,否则返回False。
根据图的正式定义,可以通过多种方式在Python中实现图的抽象数据类型。在使用不同的表达方式来实现图的抽象数据类型时,需要做很多取舍。有两种非常著名的图实现,它们分别是邻接矩阵和邻接表。

邻接矩阵
要实现图,最简单的方式就是使用二维矩阵。在矩阵实现中,每一行和每一列都表示图中的一个顶点。第v行和第w列交叉的格子中的值表示从顶点v到顶点w的边的权重。如果两个顶点被一条边连接起来,就称它们是相邻的。下图展示了上图对应的邻接矩阵。格子中的值表示从顶点v到顶点w的边的权重。
在这里插入图片描述
邻接矩阵的优点是简单。对于小图来说,邻接矩阵可以清晰地展示哪些顶点是相连的。但是,图中的绝大多数单元格是空的,我们称这种矩阵是“稀疏”的。对于存储稀疏数据来说,矩阵并不高效。事实上,要在Python中创建如图所示的矩阵结构并不容易。
邻接矩阵适用于表示有很多条边的图。但是,“很多条边”具体是什么意思呢?要填满矩阵,共需要多少条边?由于每一行和每一列对应图中的每一个顶点,因此填满矩阵共需要|V|^2条边。当每一个顶点都与其他所有顶点相连时,矩阵就被填满了。在现实世界中,很少有问题能够达到这种连接度。

邻接表
为了实现稀疏连接的图,更高效的方式是使用邻接表。在邻接表实现中,为图对象的所有顶点保存一个主列表,同时为每一个顶点对象都维护一个列表,其中记录了与它相连的顶点。在对Vertex类的实现中,使用字典(而不是列表),字典的键是顶点,值是权重。下图展示了上图所对应的邻接表。
在这里插入图片描述
邻接表的优点是能够紧凑地表示稀疏图。此外,邻接表也有助于方便地找到与某一个顶点相连的其他所有顶点。

实现
在Python中,通过字典可以轻松地实现邻接表。
要创建两个类:Graph类存储包含所有顶点的主列表,Vertex类表示图中的每一个顶点。
Vertex使用字典connectedTo来记录与其相连的顶点,以及每一条边的权重。代码展示了Vertex类的实现,其构造方法简单地初始化id(它通常是一个字符串),以及字典connectedTo。addNeighbor方法添加从一个顶点到另一个的连接。getConnections方法返回邻接表中的所有顶点,由connectedTo来表示。getWeight方法返回从当前顶点到以参数传入的顶点之间的边的权重。
在这里插入图片描述
Graph类的实现如代码所示,其中包含一个将顶点名映射到顶点对象的字典。在图7-4中,该字典对象由灰色方块表示。Graph类也提供了向图中添加顶点和连接不同顶点的方法。getVertices方法返回图中所有顶点的名字。此外,我们还实现了__iter__方法,从而使遍历图中的所有顶点对象更加方便。总之,这两个方法使我们能够根据顶点名或者顶点对象本身遍历图中的所有顶点。
在这里插入图片描述
下面的Python会话使用Graph类和Vertex类创建了如上图所示的图。首先创建6个顶点,依次编号为0~5。然后打印顶点字典。注意,对每一个键,我们都创建了一个Vertex实例。接着,添加将顶点连接起来的边。最后,用一个嵌套循环验证图中的每一条边都已被正确存储。
在这里插入图片描述

广度优先搜索

从一个例子引入:将单词FOOL转换成SAGE。在解决词梯问题时,必须每次只替换一个字母,并且每一步的结果都必须是一个单词,而不能是不存在的词。
FOOL–POOL–POLL–POLE–PALE–SALE–SAGE
这里研究的是从起始单词转换到结束单词所需的最小步数。
使用图算法来解决这个问题。以下是大致步骤:
用图表示单词之间的关系;
用一种名为宽度优先搜索的图算法找到从起始单词到结束单词的最短路径。

如果两个单词的区别仅在于有一个不同的字母,就用一条边将它们相连。如果能创建这样一个图,那么其中的任意一条连接两个单词的路径就是词梯问题的一个解。它是无向图,并且边没有权重。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值