python最小生成树kruskal与prim算法

kruskal算法基本思路:先对边按权重从小到大排序,先选取权重最小的一条边,如果该边的两个节点均为不同的分量,则加入到最小生成树,否则计算下一条边,直到遍历完所有的边。

prim算法基本思路:所有节点分成两个group,一个为已经选取的selected_node(为list类型),一个为candidate_node,首先任取一个节点加入到selected_node,然后遍历头节点在selected_node,尾节点在candidate_node的边,选取符合这个条件的边里面权重最小的边,加入到最小生成树,选出的边的尾节点加入到selected_node,并从candidate_node删除。直到candidate_node中没有备选节点(这个循环条件要求所有节点都有边连接,即边数要大于等于节点数-1,循环开始前要加入这个条件判断,否则可能会有节点一直在candidate中,导致死循环)。

#coding=utf-8
class Graph(object):
    def __init__(self, maps):
        self.maps = maps
        self.nodenum = self.get_nodenum()
        self.edgenum = self.get_edgenum()

    def get_nodenum(self):
        return len(self.maps)

    def get_edgenum(self):
        count = 0
        for i in range(self.nodenum):
            for j in range(i):
                if self.maps[i][j] > 0 and self.maps[i][j] < 9999:
                    count += 1
        return count

    def kruskal(self):
        res = []
        if self.nodenum <= 0 or self.edgenum < self.nodenum-1:
            return res
        edge_list = []
        for i in range(self.nodenum):
            for j in range(i,self.nodenum):
                if self.maps[i][j] < 9999:
                    edge_list.append([i, j, self.maps[i][j]])#按[begin, end, weight]形式加入
        edge_list.sort(key=lambda a:a[2])#已经排好序的边集合
        
        group = [[i] for i in range(self.nodenum)]
        for edge in edge_list:
            for i in range(len(group)):
                if edge[0] in group[i]:
                    m = i
                if edge[1] in group[i]:
                    n = i
            if m != n:
                res.append(edge)
                group[m] = group[m] + group[n]
                group[n] = []
        return res

    def prim(self):
        res = []
        if self.nodenum <= 0 or self.edgenum < self.nodenum-1:
            return res
        res = []
        seleted_node = [0]
        candidate_node = [i for i in range(1, self.nodenum)]
        
        while len(candidate_node) > 0:
            begin, end, minweight = 0, 0, 9999
            for i in seleted_node:
                for j in candidate_node:
                    if self.maps[i][j] < minweight:
                        minweight = self.maps[i][j]
                        begin = i
                        end = j
            res.append([begin, end, minweight])
            seleted_node.append(end)
            candidate_node.remove(end)
        return res

max_value = 9999
row0 = [0,7,max_value,max_value,max_value,5]
row1 = [7,0,9,max_value,3,max_value]
row2 = [max_value,9,0,6,max_value,max_value]
row3 = [max_value,max_value,6,0,8,10]
row4 = [max_value,3,max_value,8,0,4]
row5 = [5,max_value,max_value,10,4,0]
maps = [row0, row1, row2,row3, row4, row5]
graph = Graph(maps)
print('邻接矩阵为\n%s'%graph.maps)
print('节点数据为%d,边数为%d\n'%(graph.nodenum, graph.edgenum))
print('------最小生成树kruskal算法------')
print(graph.kruskal())
print('------最小生成树prim算法')
print(graph.prim())

初始的图如下。


运行结果如下。


  • 9
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Prim算法实现: ```Python from heapq import heappush, heappop # 堆优化 from collections import defaultdict def prim(graph, start): mst = defaultdict(set) # 存储最小生成树的结果 visited = set([start]) # 已经访问过的节点 edges = [ (cost, start, to) for to, cost in graph[start].items() ] # 从起始节点开始的所有边 # 将边按照权值排序 edges.sort() # 遍历每一条边 while edges: cost, frm, to = heappop(edges) # 取出当前最小的边 if to not in visited: # 如果该节点未访问过,加入最小生成树 visited.add(to) mst[frm].add(to) for to_next, cost in graph[to].items(): # 将新加入的节点的边加入边集中 if to_next not in visited: heappush(edges, (cost, to, to_next)) return mst ``` Kruskal算法实现: ```Python def kruskal(graph): mst = defaultdict(set) # 存储最小生成树的结果 vertices = set(graph.keys()) # 所有节点 edges = [ (graph[v1][v2], v1, v2) for v1 in vertices for v2 in graph[v1] ] # 所有边 # 将边按照权值排序 edges.sort() # 遍历每一条边 for cost, frm, to in edges: if to not in vertices: # 如果该边的终点不在当前最小生成树中,加入该边 continue vertices.remove(to) mst[frm].add(to) mst[to].add(frm) return mst ``` 其中,图的数据结构可以使用字典来表示,例如: ```Python graph = { 'A': {'B': 2, 'D': 6}, 'B': {'A': 2, 'C': 3, 'D': 8}, 'C': {'B': 3}, 'D': {'A': 6, 'B': 8}, } ``` 其中,每个键(例如'A')表示一个节点,对应的值(例如{'B': 2, 'D': 6})表示与该节点相连的边及其权值。例如,图中节点'A'与节点'B'之间的边权为2,节点'A'与节点'D'之间的边权为6。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值