Algorytmy i struktury danych -...

25
Algorytmy i struktury danych Wykład 8 - Drzewa i algorytmy ich przetwarzania Janusz Szwabiński Plan wykładu: Przykłady drzew Pojęcia i definicje Reprezentacje drzew Drzewa wyprowadzenia (ang. parse trees ) Przechodzenie drzewa Kopiec binarny Kolejka priorytetowa Źródła: większość ilustracji i przykładów pochodzi z "Problem Solving with Algorithms and Data Structures using Python", http://interactivepython.org/runestone/static/pythonds/index.html Przykłady drzew Systematyka biologiczna

Transcript of Algorytmy i struktury danych -...

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

Systemplików

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)