算法练习,最小生成树的prim,kruskal算法

prim 算法和kruskal都属于贪婪算法,其中prim算法更接近图的广度优先遍历,取一个点,找能选的权值最小的边;而kruskal则是把边按照从小到大排,如果新加的边的两个端点都被遍历过,就需要检查这两个点是否已经在一个连通通路里面。


python的练习代码

#!/usr/bin/env python
import sys,cPickle
from random import choice
from heap import MinHeap as mpq
class Vertex(object):
    def __init__(self,value=None):
        self.value=value
    def __str__(self):
        return str(self.value)
    def __repr__(self):
        return str(self.value)
class Edge(object):
    def __init__(self,weight=None,v1=None,v2=None):
        self.weight=weight
        self.v1=v1
        self.v2=v2
    def __str__(self):
        return str((self.v1,self.v2))+'-->%d'%self.weight
    def __repr__(self):
        return str((self.v1,self.v2))+'-->%d'%self.weight
    def __cmp__(self,value):
        if self.weight<value:
            return -1
        elif self.weight==value:
            return 0
        else:
            return 1
    def another_v(self,v):
        if self.v1 is not v:
            return self.v1
        elif self.v2 is not v:
            return self.v2
        else:
            return None
class UDGraph(object):
    """using adjancency list to present a undirected graph"""
    def __init__(self,vlist=None,elist=None):
        if vlist is None:
            self.vlist=[]
            self.elist=[]
            self.adlist=[]
        else:
            self.vlist=vlist
            if elist is None:
                self.elist=[]
                self.adlist=[]
                for i in range(self.vnum):
                    self.adlist.append([])
            else:
                for E in elist:
                    self.insert_e(E)
    @property
    def v_num(self):
        return len(self.vlist)
                                                                        
    def insert_v(self,V):
        self.vlist.append(V)
        self.adlist.append([])
    def insert_e(self,E):
        try:
            i1=self.vlist.index(E.v1)
            i2=self.vlist.index(E.v2)
        except ValueError:
            return -1
        else:
            self.elist.append(E)
            if i1==i2:
                self.adlist[i1].append(E)
            else:
                self.adlist[i1].append(E)
                self.adlist[i2].append(E)
    def delete_v(self,V):
        try:
            i=self.vlist.index(v)
        except ValueError:
            return -1
        else:
            for E in self.adlist[i]:
                a=E.another_v(v)
                if a is not None:
                    ia=self.vlist.index(a)
                    self.adlist[ia].remove(E)
            self.adlist.remove(adlist[i])
            self.elist.remove(E)
            self.vlist.remove(v)
                                                                        
    def delete_e(self,E):
        if E not in self.elist:
            sys.stderr.write(str(E)+' doest belong to this graph')
        v1,v2=E.v1,E.v2
        i1=self.vlist.index(v1)
        i2=self.vlist.index(v2)
        if i1!=i2:
            self.adlist[i2].remove(E)
        self.adlist[i1].remove(E)
        self.elist.remove(E)
                                                                                    
    #def MST(self,method=0):
    #    if method==0:
    #        return self._kruskal()
    #    elif method==1:
    #        return self._prim()
    #    else:
    #        sys.stderr.write('not support yet')
    #        return -1
                                                                        
    def prim(self):
        Q=UDGraph()
        for vertex in self.vlist:
            vertex.c=False
        v=choice(self.vlist)
        Q.insert_v(v)
        v.c=True
        q=mpq()
        flag=True
        wsum=0
        while flag:
            i=self.vlist.index(v)
            for e in self.adlist[i]:
                a=e.another_v(v)
                if a is None or a.c:
                    continue
                else:
                    q.push(e)
            while True:
                try:
                    e1=q.pop()
                except IndexError:
                    flag=False
                    break
                else:
                    v1,v2=e1.v1,e1.v2
                    if v1.c and v2.c:
                        continue
                    else:
                        v=v2 if v1.c else v1
                        Q.insert_v(v)
                        Q.insert_e(e1)
                        wsum+=e1.weight
                        v.c=True
                        break
        for vertex in self.vlist:
            delattr(vertex,'c')
        if len(Q.vlist)<len(self.vlist):
            sys.stderr.write('this graph is not connected graph\n')
            return -1
        else:
            print 'sum of weight is %d'%wsum
            return Q
    def kruskal(self):
        Q=UDGraph()
        findmap=[0]*len(self.vlist)
        q=sorted(self.elist,reverse=True)
        wsum=0
        c=0
        while True:
            try:
                e=q.pop()
            except IndexError:
                break
            else:
                v1,v2=e.v1,e.v2
                i1=self.vlist.index(v1)
                i2=self.vlist.index(v2)
                if findmap[i1]==findmap[i2] and findmap[i1]!=0:
                        continue
                elif findmap[i1]==findmap[i2]==0:
                        c+=1
                        Q.insert_v(v1)
                        Q.insert_v(v2)
                        Q.insert_e(e)
                        findmap[i1]=findmap[i2]=c
                        wsum+=e.weight
                elif findmap[i1]==0 and findmap[i2]!=0:
                    findmap[i1]=findmap[i2]
                    Q.insert_v(v1)
                    Q.insert_e(e)
                    wsum+=e.weight
                elif findmap[i1]!=0 and findmap[i2]==0:
                    findmap[i2]=findmap[i1]
                    Q.insert_v(v2)
                    Q.insert_e(e)
                    wsum+=e.weight
                else:
                    k=findmap[i2]
                    for i,x in enumerate(findmap):
                        if x==k:
                            findmap[i]=findmap[i1]
                    Q.insert_e(e)
                    wsum+=e.weight
        if Q.vlist<self.vlist:
            sys.stderr.write('this graph is not connected graph\n')
            return -1
        else:
            print 'sum of weight is %d'%wsum
            return Q
    def show(self):
        print self.vlist
        print self.elist
def makegraph():
    f=file('graph.dat','w')
    G=UDGraph()
    for i in range(97,106):
        G.insert_v(Vertex(chr(i)))
    G.insert_e(Edge(4,G.vlist[0],G.vlist[1]))
    G.insert_e(Edge(8,G.vlist[1],G.vlist[2]))
    G.insert_e(Edge(7,G.vlist[2],G.vlist[3]))
    G.insert_e(Edge(9,G.vlist[3],G.vlist[4]))
    G.insert_e(Edge(10,G.vlist[4],G.vlist[5]))
    G.insert_e(Edge(2,G.vlist[5],G.vlist[6]))
    G.insert_e(Edge(1,G.vlist[6],G.vlist[7]))
    G.insert_e(Edge(7,G.vlist[7],G.vlist[8]))
    G.insert_e(Edge(11,G.vlist[1],G.vlist[7]))
    G.insert_e(Edge(2,G.vlist[2],G.vlist[8]))
    G.insert_e(Edge(14,G.vlist[3],G.vlist[5]))
    G.insert_e(Edge(4,G.vlist[2],G.vlist[5]))
    G.insert_e(Edge(6,G.vlist[6],G.vlist[8]))
    G.insert_e(Edge(8,G.vlist[0],G.vlist[7]))
    cPickle.dump(G,f)
    f.close()
def test():
    f=file('graph.dat','r')
    G=cPickle.load(f)
    T=G.kruskal()
    T.show()
if __name__=='__main__':
    test()


prim算法里的最小优先级队列算法就用我刚做的,实际上python已经有了heapq的封装。纯粹当练习了。算法导论里面提到可以用fibonacci堆将二叉堆做优化,可以把prim 算法的复杂度从O(ElgV)降低到O(E+VlgV),这个以后再研究吧

你可能感兴趣的:(最小生成树)