二、7.python图

图是由边或弧连接的节点组成的网络。在有向图中,节点之间的连接有一个方向,称为弧; 在无向图中,连接没有方向,称为边。我们主要讨论有向图。图中的算法包括找到两个节点之间的路径,找到两个节点之间的最短路径,确定图中的周期(周期是从节点到自身的非空路径),找到到达所有节点的路径(着名的“旅行商问题”),等等。有时图的节点或弧具有与它们相关的权重或成本,我们有兴趣找到最便宜的路径。
关于图算法的文献很多,它们是离散数学的重要组成部分。图形在计算机算法中也有很多实际用途。在网络管理中可以找到明显的例子,但许多其他领域的例子比比皆是。例如,计算机程序中的调用者 - 被调用者关系可以被视为图形(其中周期指示递归,而不可达的节点表示死代码)。

很少有编程语言直接支持图形作为数据类型,Python也不例外。但是,图表很容易从列表和词典中构建。例如,这是一个简单的图形(我不能在这些列中使用图纸,所以我写下图形的弧形):

A  - > B 
A  - > C 
B  - > C 
B  - > D 
C  - > D 
D  - > C 
E  - > F 
F  - > C

该图有六个节点(AF)和八个弧。它可以由以下Python数据结构表示:
graph = {‘A’:[‘B’,‘C’],
‘B’:[‘C’,‘D’],
‘C’:[‘D’],
‘D’:[‘C’] ,
‘E’:[‘F’],
‘F’:[‘C’]}
这是一个字典,其键是图的节点。对于每个键,相应的值是一个列表,其中包含通过此节点的直接弧连接的节点。这很简单(更简单的是,节点可以用数字而不是名字来表示,但名称更方便,可以很容易地携带更多信息,例如城市名称)。
让我们编写一个简单的函数来确定两个节点之间的路径。它需要一个图形,并将起始和结束节点作为参数。它将返回包含路径的节点列表(包括开始和结束节点)。如果找不到路径,则返回None。同一节点在返回的路径上不会出现多次(即它不包含循环)。该算法使用一种称为回溯的重要技术:它依次尝试每种可能性,直到找到解决方案。

def find_path(graph, start, end, path=[]):
        path = path + [start]
        if start == end:
            return path
        if not graph.has_key(start):
            return None
        for node in graph[start]:
            if node not in path:
                newpath = find_path(graph, node, end, path)
                if newpath: return newpath
        return None
A sample run (using the graph above):
    >>> find_path(graph, 'A', 'D')
    ['A', 'B', 'C', 'D']
    >>> 

第二个“if”语句仅在有节点被列为弧的终点但是本身没有传出弧的情况下才是必需的,并且根本没有在图中列出。这样的节点也可以包含在图中,带有一个空的传出弧列表,但有时不需要这样就更方便。
请注意,当用户使用三个参数调用find_graph()时,它会使用第四个参数调用自身:已遍历的路径。此参数的默认值是空列表’[]’,表示尚未遍历任何节点。该参数用于避免循环(‘for’循环中的第一个’if’)。‘path’参数未被修改:赋值“path = path + [start]”创建一个新列表。如果我们改写了“path.append(start)”,我们就会在调用者中修改变量’path’,结果是灾难性的。(使用元组,我们可以肯定这不会发生,代价是必须编写“path = path +(start,)”,因为“(start)”不是单例元组 - 它只是一个带括号的元组表达。)

更改此函数以返回所有路径(无循环)的列表而不是它找到的第一个路径很简单:

 def find_all_paths(graph, start, end, path=[]):
        path = path + [start] #避免在调用者中修改path?
        if start == end:
            return [path] #把path当成paths的元素
        if not graph.has_key(start):
            return []
        paths = []
        for node in graph[start]:
            if node not in path:
                newpaths = find_all_paths(graph, node, end, path)
                for newpath in newpaths:
                    paths.append(newpath)
        return paths

示例运行:
>>> find_all_paths(graph,‘A’,‘D’)
[[‘A’,‘B’,‘C’,‘D’],[‘A’,‘B’,‘D’],[’ A’,‘C’,‘D’]]

找到最短路径:

 def find_shortest_path(graph, start, end, path=[]):
        path = path + [start]
        if start == end:
            return path
        if not graph.has_key(start):
            return None
        shortest = None
        for node in graph[start]:
            if node not in path:
                newpath = find_shortest_path(graph, node, end, path)
                if newpath:
                    if not shortest or len(newpath) < len(shortest):
                        shortest = newpath
        return shortest

find_shortest_path(图形,‘A’,‘D’)
[‘A’,‘C’,‘D’]

猜你喜欢

转载自blog.csdn.net/q386538588/article/details/86571230