数据结构之图(二)

1 邻接矩阵

        种类:一维数组和二维数组

        一维数组:存储图中顶点自身的信息

        二维数组:存储图中顶点间邻接关系的矩阵

2 最小生成树

        生成树:连通图的生成树是包含全部顶点的一个极小连通子图,可用DFS和BFS生成。

        生成树的代价:在无向连通网中,生成树上各边的权值之和

        最小生成树:在无向连通网中,代价最小的生成树

        性质:各边权值互不相等时,最小生成树是唯一的,边数为顶点数-1

3  Prim算法

        定义:从没一个顶点开始构建生成树,每次将代价最小的顶点纳入生成树,直到所有顶点都纳入为止(基于贪心算法)

python代码如下所示:

其中实现每次取出代价最小的边时,这里采用sort()内置函数,复杂度为O(nlogn),当图过大时,可能效果较差,可以使用heapq函数库,使用小根堆的结构,来优化,这样每次更新时,复杂度为O(logn)

from collections import defaultdict
def prim(vertex,egdes,start='A'):
    adiacent = defaultdict(list)
    for weight,v1,v2 in egdes:
        adiacent[v1].append([weight,v1,v2])
        adiacent[v2].append([weight,v2,v1])
    minu_tree = []
    visited = set()
    visited.add(start)
    stack = [i for i in adiacent[start]]
    while stack:
        stack.sort(key=lambda x:x[0])
        cur_minpath = stack.pop(0)
        if cur_minpath[2] not in visited:
            visited.add(cur_minpath[2])
            minu_tree.append(cur_minpath)
            for next_path in adiacent[cur_minpath[2]]:
                stack.append(next_path)
    return minu_tree
vertices = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
edges = [(7, 'A', 'B'),
         (5, 'A', 'D'),
         (8, 'B', 'C'),
         (9, 'B', 'D'),
         (7, 'B', 'E'),
         (5, 'C', 'E'),
         (15, 'D', 'E'),
         (6, 'D', 'F'),
         (8, 'E', 'F'),
         (9, 'E', 'G'),
         (11, 'F', 'G')]
print(prim(vertices, edges, start='D'))

4 Dijkstra算法

        基本原理:该算法是基于广度优先搜索的,适用于带权图和非带权图,不适用于带负权的图。

        基本步骤:

        1.找出当前离起点最近的节点

        2.对于该节点的邻居,检查是否有前往它们的更短路径,如果有,就更新,并更新邻居的父节点

        3.重复过程2,直至遍历全部节点

        4.计算最终路径

        举个例子:如下图所示,如果想要计算点D到各个节点的最短路径,则需要按照上述公式一次遍历更新。

         首先定义一个矩阵长为图中点的个数:[inf, inf, inf, 0, inf, inf, inf],除了出发点自身下标对应值设置为0意外,其余全为无穷大。

        然后遍历与D相邻的所有点,更新对应距离,如D与C之间为3,与E之间为4,故更新之后矩阵为[inf, inf, 3, 0, 4, inf, inf],此时下一轮遍历的点为(C,E),接着遍历与C相邻的所有点(B,F,E),得到矩阵[inf, 13, 3, 0, 4, 9, inf],此时下一轮遍历的点为(E,B,F),然后遍历E,得到矩阵[inf, 13, 3, 0, 4, 6, 12],可以发现D到F的值更新了。

python实现代码如下:

from collections import defaultdict
def dijstra(nodes,edges,ip='A'):
    mapper = defaultdict(list)
    node_num = len(nodes)
    path = [float('inf')]*node_num
    for start,end,weight in edges:
        mapper[start].append([end,weight])
        mapper[end].append([start,weight])
    path[ord(ip)-ord('A')]=0
    print(path)
    visited = set()
    visited.add(ip)
    stack = [ip]
    while stack:
        node = stack.pop(0)
        for next_node,weight in mapper[node]:
            path[ord(next_node)-ord('A')]=min(path[ord(next_node)-ord('A')],path[ord(node)-ord('A')]+weight)
            if next_node not in visited:
                stack.append(next_node)
                visited.add(next_node)
        print(path)
    return path

nodes = 'ABCDEFG'
egdes = [
    ['A','B',12],['A','F',16],['A','G',14],['B','C',10],
    ['B','F',7],['C','F',6],['C','D',3],['C','E',5],
    ['F','G',9],['F','E',2],['E','G',8],['E','D',4]
]
res = dijstra(nodes,egdes,ip='D')
print(res)

下期将更新Floyd 算法,以及实现检测图中是否有环的情形。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值