首页 > 代码库 > 简单图模板 Graph

简单图模板 Graph

仿写 networkx 的功能

# -*- coding: cp936 -*-
'''
                            简单图 Graph:

要求:
    关于节点:
        功能1.add_node:
            通过 add_node 一次性加一个节点
            字符串,数字,任何可以被哈希的 python 对象都可以当做节点
            包括自定义的类型或者另一个图( 构成超图 )
        格式:
            >>> G.add_node( 1 )
    
        功能2.add_nodes_from:
            通过其他容器加入节点,比如list, dict,set,文件或者另一个图
        格式:
            >>> G.add_nodes_from( [2, 3] )
            >>> H = Graph()
            >>> H.add_path( range( 10 ) )
            >>> G.add_nodes_from( H ) # 构成超图
            
    关于边:
        功能1.add_edge:
            加入一条边
        格式:
            >>> G.add_edge( 1, 2 ) # 在节点 1 和节点 2 之间加一条边
            
        功能2.add_edges_from:
            加入边集
        格式:
            >>> G.add_edges_from( [ ( 2, 4 ), ( 1, 3 ) ] ) # 通过边集来加边
            >>> G.add_edges_from( H.edges() ) # 通过另一个容器来加边
        注:
            当加边操作的两个节点不存在时,会自动创建出来

    关于属性:
        每个图,边,节点都可以拥有 '键值对' 属性
        初始时都为空,但是允许被动态添加和修改属性
        可以通过 add_node, add_edge 操作,或者直接对节点,边,图的字典进行修改
        功能1.节点属性:
            >>> G = Graph( name = 'scheme' )
            >>> G.graph
            { 'name': 'scheme' }
            
            >>> G.add_node( 1, city = 'Nanjing' )
            >>> G.nodes[1]
            { 'city': 'Nanjing' }
            
            >>> G.node
            { 1: {'city': 'Nanjing'} }
            
            >>> G.add_node( 1 ) # 但是再加入相同的节点时,属性不会消失掉
            >>> G.node
            {1: {'city': 'Nanjing'}}

            >>> G.add_node( 1, nowtime = '8:00' ) # 加入相同的节点,带上新的属性时,原来的属性会被更新
            >>> G.node
            {1: { 'city': 'Nanjing', 'nowtime': '8:00' } }

            >>> G.add_node( 1, nowtime = '8:10' )
            >>> G.node
            {1: { 'city': 'Nanjing', 'nowtime': '8:10' } }
            

            >>> G.nodes[1]['nowtime'] = '10:00' # 但是当节点 1 不存在时,这样写属性需要报错
            >>> del G.nodes[1]['nowtime']

            >>> G.add_nodes_from( range( 7, 9 ), city = 'shanghai' )
            注:
                pass
                
        功能2.边的属性:
            >>> G.add_edge( 1, 2 weight = 100 )
            >>> G.edge
            { 1: { 2: { 'weight': 100 } }, 2: { 1: { 'weight': 100 } } }
            
            >>> G.add_edges_from( [ ( 1, 3 ), ( 2, 3 ) ], weight = 111 )
            >>> G.edge
            { 1: { 2: { 'weight': 100 }, 3: { 'weight': 111 } },
            2: { 1: { 'weight': 100 }, 3: { 'weight': 111 } },
            3: { 1: { 'weight': 111 }, 2: { 'weight': 111 } } }
            
            >>> G.add_edges_from( [ ( 1, 3, { 'weight': 1 } ), ( 3, 4, { 'weight': 2 } ) ] )
            >>> G.edge
            { 1: { 2: { 'weight': 100 }, 3: { 'weight': 1 } },
            2: { 1: { 'weight': 100 }, 3: { 'weight': 111 } },
            3: { 1: { 'weight': 1 }, 2: { 'weight': 111 },
            4: { 'weight': 2 } }, 4: { 3: { 'weight': 2 } } }

            >>> G.edge[1][2]['weight'] = 111111 # 允许直接操作
            或者
            >>> G[1][2]['weight'] = 1111

    利用 python 的特性提供快捷操作:
        比如:
            >>> 1 in G
            True
            >>> [ n for n in G if n < 3 ] # 节点迭代
            [1, 2]
            >>> len(G) # 节点个数
            5
            >>> G[1] # 与该点相邻的所有点的属性
            { 2: { 'weight': 100 }, 3: { 'weight': 1 } }

        提供 adjacency_iter 来遍历边:
            >>> for node, nbrsdict in G.adjacency_iter():
                    for nbr, attr in nbrsdict.items():
                        if 'weight' in attr:
                            ( node, nbr, attr['weight'] )

			
            (1, 2, 100)
            (1, 3, 1)
            (2, 1, 100)
            (2, 3, 111)
            (3, 1, 1)
            (3, 2, 111)
            (3, 4, 2)
            (4, 3, 2)

            >>> [ ( start, end, attr['weight'])             for start, end, attr in G.edges( data = http://www.mamicode.com/True ) if 'weight' in attr ]>