python算法问题_基本算法问题的 Python 解法——图(Graph)问题

图(Graph)是一种用来对某些现实问题进行建模的抽象的数学结构,这些问题从逻辑上可以被划分成一系列相互连接的节点。其中的节点称为顶点(vertex),顶点之间的连接称为边(edge)。

比如地铁线路就可以看作由图表示成的运输网络。每一个顶点都代表一个地铁站,而顶点之间的边则表示两个地铁站之间的路径。如果想知道某个站点到另一个站点的最短路径,图算法就能发挥作用。实际上,图算法可以被应用到任何类型的网络问题中。

map as graph

0e90f815d070

美国最大的15个 MSA 的地图

0e90f815d070

美国最大的15个 MSA 的 graph 表示

# edge.py

from __future__ import annotations

from dataclasses import dataclass

@dataclass

class Edge:

u: int # the "from" vertex

v: int # the "to" vertex

def reversed(self) -> Edge:

return Edge(self.v, self.u)

def __str__(self) -> str:

return f"{self.u} -> {self.v}"

上面代码中的 Edge 类表示两个顶点之间的连接(即“边”),每个顶点都由整数索引表示。其中 u 用来表示第一个顶点,v 表示第二个顶点。

这里只关注非方向性的 graph,edge 是双向的。而在有向图(digraph)中,edge 可以是单向的。reversed() 方法用来返回当前 edge 的逆向形式。

# graph.py

from typing import TypeVar, Generic, List, Optional

from edge import Edge

V = TypeVar('V') # type of the vertices in the graph

class Graph(Generic[V]):

def __init__(self, vertices: List[V] = []) -> None:

self._vertices: List[V] = vertices

self._edges: List[List[Edge]] = [[] for _ in vertices]

@property

def vertex_count(self) -> int:

return len(self._vertices) # Number of vertices

@property

def edge_count(self) -> int:

return sum(map(len, self._edges)) # Number of edges

# Add a vertex to the graph and return its index

def add_vertex(self, vertex: V) -> int:

self._vertices.append(vertex)

self._edges.append([]) # Add empty list for containing edges

return self.vertex_count - 1 # Return index of added vertex

# This is an undirected graph,

# so we always add edges in both directions

def add_edge(self, edge: Edge) -> None:

self._edges[edge.u].append(edge)

self._edges[edge.v].append(edge.reversed())

# Add an edge using vertex indices (convenience method)

def add_edge_by_indices(self, u: int, v: int) -> None:

edge: Edge = Edge(u, v)

self.add_edge(edge)

# Add an edge by looking up vertex indices (convenience method)

def add_edge_by_vertices(self, first: V, second: V) -> None:

u: int = self._vertices.index(first)

v: int = self._vertices.index(second)

self.add_edge_by_indices(u, v)

# Find the vertex at a specific index

def vertex_at(self, index: int) -> V:

return self._vertices[index]

# Find the index of a vertex in the graph

def index_of(self, vertex: V) -> int:

return self._vertices.index(vertex)

# Find the vertices that a vertex at some index is connected to

def neighbors_for_index(self, index: int) -> List[V]:

return list(map(self.vertex_at, [e.v for e in self._edges[index]]))

# Look up a vertice's index and find its neighbors (convenience method)

def neighbors_for_vertex(self, vertex: V) -> List[V]:

return self.neighbors_for_index(self.index_of(vertex))

# Return all of the edges associated with a vertex at some index

def edges_for_index(self, index: int) -> List[Edge]:

return self._edges[index]

# Look up the index of a vertex and return its edges (convenience method)

def edges_for_vertex(self, vertex: V) -> List[Edge]:

return self.edges_for_index(self.index_of(vertex))

# Make it easy to pretty-print a Graph

def __str__(self) -> str:

desc: str = ""

for i in range(self.vertex_count):

desc += f"{self.vertex_at(i)} -> {self.neighbors_for_index(i)}\n"

return desc

Graph 类聚焦于 graph 的核心角色,即将顶点用边连接起来。

_vertices 列表是 Graph 类的核心,每个顶点都会被存储在该列表中。但是之后在实际引用时会使用顶点在列表中的索引。顶点本身有可能会是非常复杂的数据类型,但其索引一定会是 int 类型,相对而言更加方便使用。

graph 数据类型可以使用 adjacency lists 方式实现,每个顶点都拥有一个列表,里面包含了这个顶点连接的其他顶点。这里使用了由 edge 组成的列表再组成的列表(_edges),每个顶点都拥有一个由 edge 组成的列表,这些 edge 表示该顶点与其他顶点的连接关系。

Graph 类中实现的方法的简单介绍:

vertex_count 属性:获取 graph 中顶点的数量

edge_count 属性:获取 graph 中边的数量

add_vertex 方法:添加一个新的孤立的顶点并返回其索引

add_edge 方法:添加一条边(双向,参数是 Edge 对象)

add_edge_by_indices 方法:通过顶点索引添加新的边(参数是边的两个顶点的索引 u、v)

add_edge_by_vertices 方法:通过顶点添加新的边(参数是边的两个顶点(Vertex)对象)

vertex_at 方法:通过特定的索引查询顶点

index_of 方法:根据顶点返回其索引

neighbors_for_index 方法:根据某个顶点的索引获取其临近的顶点(参数为顶点索引)

neighbors_for_vertex 方法:根据某个顶点获取其临近的顶点(参数为顶点对象)

edges_for_index 方法:根据某个顶点的索引获取与其连接的边(参数为顶点索引)

edges_for_vertex 方法:根据某个顶点获取与其连接的边(参数为顶点对象)

__str__ 方法:友好的方式输出整个 graph

补充测试代码:

# graph.py continued

if __name__ == "__main__":

# test basic Graph construction

city_graph: Graph[str] = Graph(["Seattle", "San Francisco", "Los Angeles", "Riverside", "Phoenix", "Chicago", "Boston", "New York",

"Atlanta", "Miami&#

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值