python中的图结构——最小生成树

最小生成树

  • 最小生成树
  • 图的建立
    • 获取两结点之间边的权值 GetWeight(begin,end)
  • Prim算法
    • 基本思路
    • 代码
  • Kruskal算法
    • 基本思路
  • 代码
  • 运行结果示例
  • 两种算法的对比

最小生成树

一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。
完成构造网的最小生成树必须解决下面两个问题:

(1)尽可能选取权值小的边,但不能构成回路;

(2)选取n-1条恰当的边以连通n个顶点;

图的建立

主体部分见前一篇:https://blog.csdn.net/nanashi_F/article/details/92219999
为了能获取权值得到最小生成树,在AdGraph中添加了一个函数

获取两结点之间边的权值 GetWeight(begin,end)

    def GetWeight(self,begin,end):      #获取两结点之间边的权值
        wei=10000
        p=self.vertexList[begin].firstNode
        if p!=None:
            if p.Index==end:
                wei=p.Weight
            else:
                while p.Next!=None:
                    p=p.Next
                    if p.Index==end:
                        wei=p.Weight
        return wei

Prim算法

基本思路

所有节点分成两个group,一个为已经选取的Select,一个为未选的Candidate。
首先将已给的一个节点加入到Select,然后遍历头节点在Select、尾节点在Candidate的边,选取符合这个条件的边里面权重最小的边,加入到最小生成树,选出的边的尾节点加入到Select,并从Candidate删除。重复此操作直到Candidate中没有节点。
需要注意的是,循环开始前要保证所有节点都有边连接,否则可能会有节点一直在Candidate中,导致死循环。

代码

    def MiniSpanTree_prim(self,vName):  #最小生成树-prim
        i=self.GetIndex(vName) 
        if i==-1:
            return None
        for i in range(self.vertexCount):       #判断是否有没有边链接的节点
            if vertexList[i].firstNode==None:
                return None
        wsum=0
        Spantree=[]                     #最小生成树
        Select=[]                       #已选择节点
        Candidate=[]                    #未选择节点
        for i in range(self.vertexCount):   #初始所有节点都在Candidate中
            Candidate.append(i)
        Select.append(i)                #将根节点移入Select
        Candidate.remove(i)
        
        while len(Candidate)>0:
            [begin,end,minweight]=[-1,-1,9999]
            for i in Select:
                for j in Candidate:
                    if self.GetWeight(i,j)< minweight:  
                        minweight = self.GetWeight(i,j)
                        begin = i
                        end = j
            Spantree.append([begin, end, minweight])    #找出链接两节点集权值最小的边并加入
            wsum+=minweight
            Select.append(end)
            Candidate.remove(end)
        
        spanstr="最小生成树总权值:"+str(wsum)+'\n'     #整理输出
        Spantree = Spantree[::-1] 
        for node in Spantree:
            spanstr+=self.vertexList[node[1]].vertexName+"->"
            spanstr+=self.vertexList[node[0]].vertexName+'\n'
            spanstr+="     weight:"+str(node[2])+'\n'
        return spanstr

Kruskal算法

基本思路

先对边按权重从小到大排序,先选取权重最小的一条边,如果该边的两个节点处于不同的连通分量,则加入到最小生成树,并将这两个连通分量合并,否则计算下一条边,直到遍历完所有的边。

代码

    def MiniSpanTree_kruskal(self):   #最小生成树-kruskal
        vertexSort=[]
        for i in range(self.vertexCount):               #整理出当前树的边集(i
            for j in range(self.vertexCount-i):
                weight=self.GetWeight(i,i+j)
                if weight<9999:                         #利用GetWeight函数鉴定两节点间是否有边
                    vertexSort.append([i,i+j,weight])
        vertexSort.sort(key=lambda a:a[2])              #对边集中的边进行排序
        
        Spantree=[]
        wsum=0
        trees = [[i] for i in range(self.vertexCount)]  #所有树的集合
        for edge in vertexSort:
            tree1=edge[0]               
            tree2=edge[1]
            for i in range(len(trees)):
                if tree1 in trees[i]:   #获取两节点分别所在的树
                    tree1 = i
                if tree2 in trees[i]:
                    tree2 = i
            if tree1 != tree2:                  #若两节点不在同一棵树上,链接两棵树
                Spantree.append(edge)
                wsum+=edge[2]
                trees[tree1] = trees[tree1] + trees[tree2]
                trees[tree2] = []
        
        spanstr="最小生成树总权值:"+str(wsum)+'\n'         #整理输出
        for node in Spantree:
            spanstr+=self.vertexList[node[0]].vertexName+"->"
            spanstr+=self.vertexList[node[1]].vertexName+'\n'
            spanstr+="     weight:"+str(node[2])+'\n'
        return spanstr

运行结果示例

python中的图结构——最小生成树_第1张图片

两种算法的对比

因为kruskal算法需要对图中所有的边根据权值进行排序并储存,所以在图比较复杂的时候可能会占用大量空间。

所以,一般来说:
prim算法适合稠密图
kruskal算法适合简单图

你可能感兴趣的:(数据结构)