AlgorytmyistrukturydanychWykład8-Drzewaialgorytmyichprzetwarzania
JanuszSzwabiński
Planwykładu:
PrzykładydrzewPojęciaidefinicjeReprezentacjedrzewDrzewawyprowadzenia(ang.parsetrees)PrzechodzeniedrzewaKopiecbinarnyKolejkapriorytetowa
Źródła:większośćilustracjiiprzykładówpochodziz"ProblemSolvingwithAlgorithmsandDataStructuresusingPython",http://interactivepython.org/runestone/static/pythonds/index.html
Przykładydrzew
Systematykabiologiczna
In[7]:
!tree-d-L2/home/szwabin/Dropbox/Zajecia/
/home/szwabin/Dropbox/Zajecia/├──AlgorytmyIStrukturyDanych│├──Lab│└──Materiały├──Cwiczenia│└──PythonIntro├──PythonIntro│├──PWr│└──UWr└──WstepDoProgramowania├──Cwiczenia├──Egzamin├──Laboratoria├──Przykłady└──Wyklady
14directories
DrzewoznacznikówHTML<htmlxmlns="http://www.w3.org/1999/xhtml"xml:lang="en"lang="en"><head><metahttp-equiv="Content-Type"content="text/html;charset=utf-8"/><title>simple</title></head><body><h1>Asimplewebpage</h1><ul><li>Listitemone</li><li>Listitemtwo</li></ul><h2><ahref="http://wmat.pwr.edu.pl/index.dhtml">WydziałMatematykiPWr</a><h2></body></html>
Drzewaskładniowe
PojęciaidefinicjeWęzełlubwierzchołek(ang.node)-podstawowyelementdrzewa:
możemiećnazwę,czyliklucz(ang.key)możezawieraćdodatkowedane(ang.payload)daneteniemajązregułyznaczeniadlaalgorytmówdotyczącychdrzew,sąjednakbardzoważnewzastosowaniach
Krawędź(ang.edge)-kolejnyważnyelementdrzewa:łączyzesobąwierzchołki,abyzaznaczyćrelacjęmiędzynimikażdywierzchołek(opróczkorzenia)majednąkrawędźwchodzącą,łączącągozrodzicemkażdywierzchołekmożemiećwielekrawędziwychodzących
Korzeń(ang.root)-jedynywierzchołek,któryniemakrawędziwchodzącej(niemarodzica)Ścieżka(ang.path)-uporządkowanalistawierzchołkówzłączącymiichkrawędziami:
Mammal → Carnivora → Felidae → Felis → DomesticaDziecko(ang.child,childnode)-węzełpołączonykrawędziąwchodzącązinnymwęzłemjestjegodzieckiemRodzic(ang.parent)-węzełpołączonykrawędziąwychodzącązinnymwęzłemjestjegorodzicemRodzeństwo(ang.siblings)-wszystkiewęzłymającetegosamegorodzicaPotomek(ang.descendant)-potomkamiwęzłanazywamywszystkiewęzły,doktórychprowadziodniegościeżkaPoddrzewo(ang.subtree)-zbiórwęzłówikrawędzizłożonyzwybranegowęzła(rodzica)iwszystkichjegopotomkówLiść(ang.leaf)-wierzchołek,któryniemadzieciDługość(ang.length)-liczbakrawędziwścieżceodkorzeniadowęzłaPoziom(ang.level)-toinaczejdługośćodkorzeniaWysokość(ang.height)-najwyższypoziomistniejącywdrzewie
Drzewo-definicja1zbiórwierzchołkówikrawędziłączącychparywęzłówwłasności:
jedenwyróżnionywęzeł-korzeń,któryniemarodzicakażdywęzełn(zwyjątkiemkorzenia)jestpołączonydokładniejednąkrawędziąwchodzącązwęzłemp.Węzełpjestrodzicemwęzłanistniejetylkojednaścieżkałączącadowolnywęzełzkorzeniem
jeślikażdywęzełmożemiećconajwyżej2dzieci,mówimyodrzewachbinarnych
Drzewo-definicja2drzewojestalbopustealbozawierakorzeńipewnąliczbąpoddrzew,zktórychkażdejestdrzewemkorzeńpoddrzewajestpołaczonyzkorzeniemdrzewagłównegokrawędzią
Reprezentacjedrzew
Listalist
napodstawiedefinicjirekurencyjnejwbudowanelistywPythoniepierwszyelementlistytokorzeń,drugitolewepoddrzewo,trzeci-prawepoddrzewo
In[3]:
myTree=['a',#root['b',#leftsubtree['d',[],[]],#leftsubtreeoftheleftsubtree['e',[],[]]],#rightsubtreeoftheleftsubtree['c',#rightsubtree['f',[],[]],#leftsubtreeoftherightsubtree[]]#rightsubtreeoftherightsubtree(empty)]
In[4]:
myTree
doposzczególnychelementówodnosimysięprzypomocystandardowychindeksówlistkorzeńtomyTree[0]lewepoddrzewotomyTree[1],prawe-myTree[2]
In[5]:
print(myTree)print('leftsubtree=',myTree[1])print('root=',myTree[0])print('rightsubtree=',myTree[2])
poddrzewaodczytujemywtensamsposóbreprezentacjamastrukturęrekurencyjną
In[6]:
print('rootofleftsubtree=',myTree[1][0])print('leftsubtreeoftheleftsubtree=',myTree[1][1])print('rightsubtreeoftheleftsubtree=',myTree[1][2])
podrzewo,któremakorzeńidwiepustelistytopoprostuliśćreprezentacjęmożnauogólnićdowiększejliczbypotomków-każdekolejnepoddrzewotonastępnalista
Out[4]:
['a',['b',['d',[],[]],['e',[],[]]],['c',['f',[],[]],[]]]
['a',['b',['d',[],[]],['e',[],[]]],['c',['f',[],[]],[]]]leftsubtree=['b',['d',[],[]],['e',[],[]]]root=arightsubtree=['c',['f',[],[]],[]]
rootofleftsubtree=bleftsubtreeoftheleftsubtree=['d',[],[]]rightsubtreeoftheleftsubtree=['e',[],[]]
Konstruktor
In[18]:
defBinaryTree(r):return[r,[],[]]
Wstawianieelementów
abydodaćlewepoddrzewo,musimywstawićnowąlistęwmiejscedrugiegoelementulistyreprezentującejdrzewojeśliwliścienadrzędnejjestjużjakiśobiektnadrugiejpozycji:
ściągamygozlistyizapamiętujemywartośćwstawiamypoddrzewozapamiętanyelementwstawiamyjakolewedzieckotegopoddrzewa
takzdefiniowanafunkcjapozwolinamwstawićpoddrzewowdowolnymwierzchołkudrzewanadrzędnego
In[19]:
definsertLeft(root,newBranch):t=root.pop(1)iflen(t)>1:root.insert(1,[newBranch,t,[]])else:root.insert(1,[newBranch,[],[]])returnroot
funkcjawstawiającaprawepoddrzewojestbardzopodobna:
In[20]:
definsertRight(root,newBranch):t=root.pop(2)iflen(t)>1:root.insert(2,[newBranch,[],t])else:root.insert(2,[newBranch,[],[]])returnroot
Inneprzydatnefunkcje
In[21]:
defgetRootVal(root):returnroot[0]
defsetRootVal(root,newVal):root[0]=newVal
defgetLeftChild(root):returnroot[1]
defgetRightChild(root):returnroot[2]
In[31]:
r=BinaryTree(3)print("Initialtree:",r)insertLeft(r,4)insertLeft(r,5)insertRight(r,6)insertRight(r,7)print("Treeafterinsertions:",r)l=getLeftChild(r)print("Leftsubtree:",l)setRootVal(l,9)print("Leftsubtreeafterchangeofroot:",l)insertLeft(l,11)print("Treeafterinsertions:",r)print("Rightchildofrightchild:",getRightChild(getRightChild(r)))
Reprezentacjaprzypomocywęzłówireferencjireprezentacjataprzypominaniecoomawianąwcześniejlistęjednokierunkową
tworzymyklasę,któraprzechowujekorzeńorazreferencjedopoddrzewpodobnie,jakwpoprzedniejreprezentacji,strukturarekurencyjna
In[32]:
classBinaryTree:def__init__(self,rootObj):self.key=rootObjself.leftChild=Noneself.rightChild=None
atrybutyleftChildirightChildstanąsięreferencjamidopoddrzewrootObjwkonstruktorzetoreferencjadodowolnegoobiektukorzystajączrekurencyjnejdefinicjidrzewa,przykładpowyżejwymagałbystworzenia6instancjiklasyBinaryTree
Wstawianieelementów
abydodaćlewedzieckododrzewa,stworzymynowąinstancjędrzewabinarnego,anastępniewykorzystamyatrybutleftChild,abyodnieśćsiędoniego
Initialtree:[3,[],[]]Treeafterinsertions:[3,[5,[4,[],[]],[]],[7,[],[6,[],[]]]]Leftsubtree:[5,[4,[],[]],[]]Leftsubtreeafterchangeofroot:[9,[4,[],[]],[]]Treeafterinsertions:[3,[9,[11,[4,[],[]],[]],[]],[7,[],[6,[],[]]]]Rightchildofrightchild:[6,[],[]]
In[33]:
classBinaryTree:def__init__(self,rootObj):self.key=rootObjself.leftChild=Noneself.rightChild=NonedefinsertLeft(self,newNode):ifself.leftChild==None:self.leftChild=BinaryTree(newNode)else:t=BinaryTree(newNode)t.leftChild=self.leftChildself.leftChild=t
uwzględniliśmytutajdwaprzypadki:1. korzeńdrzewanadrzędnegoniemalewegodziecka-wtedypoprostujewstawiamy2. wstawiamynowepoddrzewowmiejsceistniejącego,przesuwająctoostatnienawyższypoziomprawepoddrzewowstawiamypodobnie:
In[34]:
classBinaryTree:def__init__(self,rootObj):self.key=rootObjself.leftChild=Noneself.rightChild=NonedefinsertLeft(self,newNode):ifself.leftChild==None:self.leftChild=BinaryTree(newNode)else:t=BinaryTree(newNode)t.leftChild=self.leftChildself.leftChild=tdefinsertRight(self,newNode):ifself.rightChild==None:self.rightChild=BinaryTree(newNode)else:t=BinaryTree(newNode)t.rightChild=self.rightChildself.rightChild=t
Funkcjepomocnicze
In[35]:
classBinaryTree:def__init__(self,rootObj):self.key=rootObjself.leftChild=Noneself.rightChild=NonedefinsertLeft(self,newNode):ifself.leftChild==None:self.leftChild=BinaryTree(newNode)else:t=BinaryTree(newNode)t.leftChild=self.leftChildself.leftChild=tdefinsertRight(self,newNode):ifself.rightChild==None:self.rightChild=BinaryTree(newNode)else:t=BinaryTree(newNode)t.rightChild=self.rightChildself.rightChild=tdefgetRightChild(self):returnself.rightChild
defgetLeftChild(self):returnself.leftChild
defsetRootVal(self,obj):self.key=obj
defgetRootVal(self):returnself.key
In[40]:
r=BinaryTree('a')print("Rootkey=",r.getRootVal())print("Leftchild=",r.getLeftChild())r.insertLeft('b')print("Leftchildafterinsertion(reference)=",r.getLeftChild())print("Leftchildafterinsertion(value)=",r.getLeftChild().getRootVal())r.insertRight('c')print("Rightchildafterinsertion(reference)=",r.getRightChild())print("Rightchildafterinsertion(value)=",r.getRightChild().getRootVal())r.getRightChild().setRootVal('hello')print("Rootkeyafterupdate=",r.getRightChild().getRootVal())
Drzewawyprowadzenia(ang.parsetrees)drzewawyprowadzeniamogąbyćstosowanedoreprezentowania:
zdańwjęzykunaturalnym,np."HomerhitBart"
Rootkey=aLeftchild=NoneLeftchildafterinsertion(reference)=<__main__.BinaryTreeobjectat0x7f813039a828>Leftchildafterinsertion(value)=bRightchildafterinsertion(reference)=<__main__.BinaryTreeobjectat0x7f813039ac18>Rightchildafterinsertion(value)=cRootkeyafterupdate=hello
wyrażeńmatematycznych,np.((7 + 3) ∗ (5 − 2))
wykorzystaniedrzewpozwalaosobnoprzetwarzaćposzczególneczęścitychstruktur(reprezentowaneprzezpoddrzewa)
TworzeniedrzewwyprowadzeniawyrażeńmatematycznychCowiemyowyrażeniachmatematycznych?:
nawiasy,operatoryioperandykażdylewynawiasrozpoczynanowedziałanie(nowepoddrzewo)każdyprawynawiaskończydziałanieoperandypowinnybyćliśćmioperatortorodzicoperandówkażdyoperatormadwojedzieci
Sposóbpostępowania:1. Przekształćwyrażenienalistęznaków.2. Przetwarzajwyrażenieznakpoznaku:
jeśliaktualnyznakto(,dodajlewedzieckodoaktualnegowęzłaiprzejdźdoniego,jeśliaktualnyznakjestnaliście['+','-','*','/'],przypiszgodoatrybutukeyaktualnegowęzła.Dodajnowywęzełjakoprawedzieckoiprzejdźdoniego,jeśliznaktoliczba,przypiszgodoatrybutukeyaktualnegowęzłaiwróćdojegorodzica,jeśliaktualnyznakto),wróćdorodzicaaktualnegowęzła.
Przykład
wyrażenie
(3 + (4 ∗ 5))
listaznaków`['(','3','+','(','4','*','5',')',')']`
krok1-drzewozpustymkorzeniem
krok2-wczytujemyznak(tworzymylewedzieckoiprzechodzimydoniego(aktualnywęzełjestszary)
krok3-wczytujemy3wstawiamywartośćdokluczaaktualnegowęzławracamydorodzica
krok4-wczytujemy+wstawiamywartośćdokluczaaktualnegowęzładodajemynowywęzełjakoprawedzieckoprzechodzimydoniego
krok5-wczytujemy(tworzymylewedzieckoaktualnegowęzłaiprzechodzimydoniego
krok6-wczytujemy4wstawiamywartośćdokluczaaktualnegowęzłaiwracamydorodzica
krok7-wczytujemy'*'wstawiamywartośćdokluczaaktualnegowęzładodajemynowywęzełjakoprawedzieckoprzechodzimydoniego
krok8-wczytujemy5wstawiamywartośćdokluczaaktualnegowęzłaiwracamydorodzica
krok9-wczytujemy)przechodzimydorodzicaaktualnegowęzła
krok10-wczytujemy)przechodzimydorodzicaaktualnegowęzłalub......kończymy,jeślijesteśmywkorzeniucałegodrzewa,któryniemarodzica
abyzaimplementowaćtęprocedurę,musimyśledzićrodzicaidzieckokażdegowęzła:wprzypadkudziecisprawajestprosta-naszaklasazawierajużodpowiednienarzędziawprzypadkurodziców-możemywykorzystaćstos:
zakażdymrazem,kiedychcemywrócićdorodzica,pobieramygozestosu
Implementacja
In[42]:
fromasdimportStack
defbuildParseTree(fpexp):fplist=fpexp.split()pStack=Stack()eTree=BinaryTree('')pStack.push(eTree)currentTree=eTreeforiinfplist:ifi=='(':currentTree.insertLeft('')pStack.push(currentTree)currentTree=currentTree.getLeftChild()elifinotin['+','-','*','/',')']:currentTree.setRootVal(int(i))parent=pStack.pop()currentTree=parentelifiin['+','-','*','/']:currentTree.setRootVal(i)currentTree.insertRight('')pStack.push(currentTree)currentTree=currentTree.getRightChild()elifi==')':currentTree=pStack.pop()else:raiseValueErrorreturneTree
In[43]:
pt=buildParseTree("((10+5)*3)")
Wykonywaniedziałańreprezentowanychwpostacidrzew
każdynawiasreprezentowanyjestpoddrzewemmożemywykonaćdziałaniarekurencyjnie,wykonującoddzielniekażdezpoddrzewprzypadekbazowy:
węzełzawierającyliczbę(czyliliść)niewymagadalszegoprzetwarzaniafunkcjawykonującadziałaniazwracapoprostujegowartość
wynikidwóchrekurencyjnychwywołańnadzieciachsąoperandamidziałaniazdefiniowanegowichrodzicu
In[45]:
importoperator
defevaluate(parseTree):opers={'+':operator.add,'-':operator.sub,'*':operator.mul,'/':operator.truediv}
leftC=parseTree.getLeftChild()rightC=parseTree.getRightChild()
ifleftCandrightC:fn=opers[parseTree.getRootVal()]returnfn(evaluate(leftC),evaluate(rightC))else:returnparseTree.getRootVal()
In[46]:
evaluate(pt)
Out[46]:
45
![Przechodzeniedrzewa](tree_traversal.png)
Przechodzeniedrzewaprzechodzeniedrzewatoprocesodwiedzaniawszystkichwęzłówdrzewawiększośćzastosowańdrzewwymagatakiejoperacjiwzależnościodkolejnościodwiedzaniarozróżniamy
przejściewzdłużne(ang.preorder)-najpierwodwiedzamykorzeń,apotemrekursywnieprzechodzimyjegolewepoddrzewo,apotemtaksamoprawepodrzewoprzejściepoprzeczne(ang.inorder)-rekursywnewykonanieprzechodzenianalewympoddrzewie,potemodwiedzamykorzeńiwykonujemyrekursywneprzechodzenieprawegopoddrzewaprzejściewsteczne(ang.postorder)-rekursywnieprzechodzimylewepoddrzewo,potemprawe,anakońcuodwiedzamykorzeń
preorder:F,B,A,D,C,E,G,I,Hinorder:A,B,C,D,E,F,G,H,Ipostorder:A,C,E,D,B,H,I,G,F
In[47]:
defpreorder(tree):iftree:print(tree.getRootVal())preorder(tree.getLeftChild())preorder(tree.getRightChild())
In[49]:
preorder(pt)
In[50]:
defpostorder(tree):iftree!=None:postorder(tree.getLeftChild())postorder(tree.getRightChild())print(tree.getRootVal())
In[51]:
postorder(pt)
wykonaniedziałaniareprezentowanegoprzezdrzewotonicinnegojakprzejściepostorder:
In[56]:
defpostordereval(tree):opers={'+':operator.add,'-':operator.sub,'*':operator.mul,'/':operator.truediv}res1=Noneres2=Noneiftree:res1=postordereval(tree.getLeftChild())res2=postordereval(tree.getRightChild())ifres1andres2:returnopers[tree.getRootVal()](res1,res2)else:returntree.getRootVal()
*+1053
105+3*
In[57]:
postordereval(pt)
In[52]:
definorder(tree):iftree!=None:inorder(tree.getLeftChild())print(tree.getRootVal())inorder(tree.getRightChild())
In[53]:
inorder(pt)
przechodzeniewporządkuinorderzwracawejściowewyrażeniebeznawiasówmożemywykorzystaćtodowypisaniawyrażenianaekranie:
In[54]:
defprintexp(tree):sVal=""iftree:sVal='('+printexp(tree.getLeftChild())sVal=sVal+str(tree.getRootVal())sVal=sVal+printexp(tree.getRightChild())+')'returnsVal
In[55]:
printexp(pt)
Kopiecbinarnystrukturadanychopartanadrzewiebinarnymwartościwęzłasąwstałejrelacjizwartościąrodzica(np.wartośćrodzicajestniemniejszaniżwartościjegopotomka)
OperacjenakopcuBinaryHeap()-tworzynowy,pustykopiecbinarnyinsert(k)-dodajelementdokopcafindMin()-zwracawartośćnajmniejszegoelementu,pozostawiagonakopcudelMin()-ściąganajmniejsząwartośćzkopcaisEmpty()-sprawdza,czykopiecjestpustysize()-zwracaliczbęelementówwkopcubuildHeap(list)-tworzykopieczlistyelementów
Własnościkopca
Strukturakopca
abyprzetwarzaniedrzewabyłowydajne(wczasielogarytmicznym),musibyćonozrównoważonezrównoważonedrzewoposiadamniejwięcejtęsamąliczbęwęzłówwobupoddrzewachzupełnedrzewobinarne:
każdypoziomdrzewa(zwyjątkiemostatniegoczyliliści)musibyćpełnyliściewstawiamysukcesywnieodlewejdoprawejtakiedrzewomożnareprezentowaćpojedyncząlistą:
jeślirodzicjestnapozycjip,jegolewedzieckomaindeks2p,ajegoprawedziecko-2p + 1
Out[57]:
45
10+5*3
Out[55]:
'(((10)+(5))*(3))'
węzełnapozycjinmarodzicanapozycjin / / 2korzeńmusimiećindeks1(zerowyelementlistyniejestwykorzystywany)
Porządekwkopcu
kluczwęzłaxjestwiększybądźrównykluczowijegorodzicap
Implementacja
Konstruktor
doreprezentacjikopcaużywamypythonowychlistwkonstruktorzewstawiamy0jakopierwszyelementlistyelementtenniebędziepóźniejużywany
In[58]:
classBinHeap:def__init__(self):self.heapList=[0]self.currentSize=0
Wstawianieelementów
najbardziejwydajnametodawstawianiaelementówdolistytodołączanieichdojejkońcawtensposóbutrzymanazostaniestrukturakopca,tzn.:
drzewopozostanieprawiepełne(liścietylkonaostatnimiewentualnieprzedostatnimpoziomie)liścienaostatnimpoziomiewstawianeodlewej
najprawdopodobniejnaruszymywtensposóbporządekkopcałatwojestjednakwymyślićmetodęnaprawieniaporządku:
przesuwającwęzełdogóry,przywracamyodpowiedniporządekmiędzywęzłemijegorodzicemporządekpozostałychpotomkówniezostajenaruszonyjeślinowyelementjestbardzomały,koniecznemożebyćwykonaniewielutakichzamian
In[59]:
classBinHeap:def__init__(self):self.heapList=[0]self.currentSize=0defpercUp(self,i):whilei//2>0:ifself.heapList[i]<self.heapList[i//2]:tmp=self.heapList[i//2]self.heapList[i//2]=self.heapList[i]self.heapList[i]=tmpi=i//2definsert(self,k):self.heapList.append(k)self.currentSize=self.currentSize+1self.percUp(self.currentSize)
Znajdowanieminimum
zewzględunaporządekwkopcu,topoprostukluczkorzenia
In[]:
classBinHeap:def__init__(self):self.heapList=[0]self.currentSize=0defpercUp(self,i):whilei//2>0:ifself.heapList[i]<self.heapList[i//2]:tmp=self.heapList[i//2]self.heapList[i//2]=self.heapList[i]self.heapList[i]=tmpi=i//2definsert(self,k):self.heapList.append(k)self.currentSize=self.currentSize+1self.percUp(self.currentSize)deffindMin(self):returnself.heapList[1]
Usuwanienajmniejszegoelementu
pousunięciunajmniejszegoelementukopca(czylikorzeniadrzewa),przywracamyjegowłasnościwdwóchkrokach:1. wstawiamyostatnielementzlistywmiejscekorzenia2. jeśliporządekzostałzburzony,przywracamygo,zamieniająckorzeńzmniejszymzjegodzieci3. kontunuujemyzamianydoodzyskaniaporządkukopca
In[60]:
classBinHeap:def__init__(self):self.heapList=[0]self.currentSize=0defpercUp(self,i):whilei//2>0:ifself.heapList[i]<self.heapList[i//2]:tmp=self.heapList[i//2]self.heapList[i//2]=self.heapList[i]self.heapList[i]=tmpi=i//2definsert(self,k):self.heapList.append(k)self.currentSize=self.currentSize+1self.percUp(self.currentSize)deffindMin(self):returnself.heapList[1]
defpercDown(self,i):while(i*2)<=self.currentSize:mc=self.minChild(i)ifself.heapList[i]>self.heapList[mc]:tmp=self.heapList[i]self.heapList[i]=self.heapList[mc]self.heapList[mc]=tmpi=mc
defminChild(self,i):ifi*2+1>self.currentSize:returni*2else:ifself.heapList[i*2]<self.heapList[i*2+1]:returni*2else:returni*2+1defdelMin(self):retval=self.heapList[1]self.heapList[1]=self.heapList[self.currentSize]self.currentSize=self.currentSize-1self.heapList.pop()self.percDown(1)returnretval
Generowaniekopcazlisty
traktujemylistęwejściowąjakokopiecdokonujemyewentualnychzmianwceluprzywróceniaporządku
In[74]:
classBinHeap:def__init__(self):self.heapList=[0]self.currentSize=0defpercUp(self,i):whilei//2>0:ifself.heapList[i]<self.heapList[i//2]:tmp=self.heapList[i//2]self.heapList[i//2]=self.heapList[i]self.heapList[i]=tmpi=i//2definsert(self,k):self.heapList.append(k)self.currentSize=self.currentSize+1self.percUp(self.currentSize)deffindMin(self):returnself.heapList[1]
defpercDown(self,i):while(i*2)<=self.currentSize:mc=self.minChild(i)ifself.heapList[i]>self.heapList[mc]:tmp=self.heapList[i]self.heapList[i]=self.heapList[mc]self.heapList[mc]=tmpi=mc
defminChild(self,i):ifi*2+1>self.currentSize:returni*2else:ifself.heapList[i*2]<self.heapList[i*2+1]:returni*2else:returni*2+1defdelMin(self):retval=self.heapList[1]self.heapList[1]=self.heapList[self.currentSize]self.currentSize=self.currentSize-1self.heapList.pop()self.percDown(1)returnretvaldefbuildHeap(self,alist):i=len(alist)//2self.currentSize=len(alist)self.heapList=[0]+alist[:]while(i>0):self.percDown(i)i=i-1defsize(self):returnself.currentSizedefisEmpty(self):returnself.currentSize==0def__str__(self):txt="{}".format(self.heapList[1:])returntxt
In[75]:
bh=BinHeap()bh.isEmpty()
Out[75]:
True
In[76]:
bh.buildHeap([9,5,6,2,3])print(bh)
In[77]:
bh.isEmpty()
In[80]:
print(bh.delMin())print(bh.delMin())print(bh.delMin())print(bh.delMin())print(bh.delMin())
In[81]:
bh.isEmpty()
In[82]:
print(bh)
[2,3,6,5,9]
Out[77]:
False
23569
Out[81]:
True
[]
Kolejkapriorytetowaprzypominakolejkę,jednakjejelementymajądodatkowyporządek(priorytet)elementyściąganesązpoczątkukolejkiimwyższypriorytetmaelement,tymbliżejpoczątkukolejkisięznajduje
możliwadozaimplementowaniaprzypomocyfunkcjisortującychilist:wstawianiedolistyjestoperacjąO(n)sortowanielistytoO(nlogn)niejesttonajwydajniejszametoda
kopiecbinarnypozwalanapobieranieiwstawianieelementówzezłożonościąO(logn)