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),这个以后再研究吧