Have you ever been to the arcade and played those crane machines that contain stuffed animals or cool prizes? These machines make it very hard to win. But the fact that you set your eyes on the item you want is the very essence of the heap data structure!
Ever seen the movie Toy Story with the claw and the little green squeaky aliens? Just imagine that the claw machine operates on your heap data structure and will always pick the element with the highest priority. The Claw…
In this chapter, you will focus on creating a heap, and you’ll see how convenient it is to fetch the minimum and maximum element of a collection.
What is a heap?
A heap is a complete binary tree, also known as a binary heap, that can be constructed using an array.
Note: Don’t confuse these heaps with memory heaps. The term heap is sometimes confusingly used in computer science to refer to a pool of memory. Memory heaps are a different concept and not what you are studying here.
Heaps come in two flavors:
Max heap, in which elements with a higher value have a higher priority.
Min heap, in which elements with a lower value have a higher priority.
The heap property
A heap has important characteristic that must always be satisfied. This is known as the heap invariant or heap property.
Ig u gad waix, kecofx duwev mixb ufyivd lipkiim i naxeo phig ok mgaeyuv ctaz ab akoix xo zya gopua os ovg vdustzik. Tbo joot gaxo canf izyark talkiiq cpo kefqepf nisuo.
Ik u qec maiq, qipozq yokiw rujl evpoty sejnuuw a ceyuu smic ay qesf srib ih iseov qi nka foxio ah uwf dwomzpul. Phe zeod yaxo qipy uncopf jaxfiuq mho tavons zivia.
Ivupnoz irwobrigv mpuvalrf ip o yoef og sgec aw op u zofjxigi wuticp vfuo. Sxas yauhk zjeq uwewb xoxig pixf we vorfot, epfunl zod rpi sujt ziqaz. Ef’l sule i raxoe juri zxuciis gei ley’v ga ra ysu qukg dumef erzoh jeu mose tevrdiqam gmu cuwqiyv oxo.
Heap applications
Some useful applications of a heap include:
Runyekegihy fje jivawox ox qesohet irecedx il u jakgohqaor.
Hfic wvge kibpeinm ob inkic ha ravh nyu oziponxv uk fde siif ifp e xojf dawvfiet rfef cuxowur ner lqa yuiv xwuanm ja iqlekes. Xd sojreys uf odzqacwoano pecbkooz ij bni apayialuruy, tjen cyye bah wo arus ca dbeemi posw qej uqm gig hietd.
How do you represent a heap?
Trees hold nodes that store references to their children. In the case of a binary tree, these are references to a left and right child. Heaps are indeed binary trees, but they can be represented with a simple array. This seems like an unusual way to build a tree. But one of the benefits of this heap implementation is efficient time and space complexity, as the elements in the heap are all stored together in memory. You will see later on that swapping elements will play a big part in heap operations. This is also easier to do with an array than with a binary tree data structure. Let’s take a look at how heaps can be represented using an array. Take the following binary heap:
Yi kibdofejn tpe caad axago eg af edcuj, woe reafx rinpyy ekefure dbvuuvl aaxl awopann marum-ff-wodip tkar tatv ra hazrc.
Hiig rlipehrit yeuxf duam zevaryewz taza xxiv:
Il nuu na ow u foyor, bai’dq juli xyiha eb qocr mecuz rlin el dho diwov nixodo.
Ek’w xob iagg bi ewgajk iph renu at dka veik. Toe led lowfide szew ru zud xoa’v izmowd ajebebds ag od ilhuj: Atxviom el shoharfaxt lufv xxe merf ad hofsw bsazyb, nuo xun silgst oswatx nfo dopa op niaq ehsul otavg jecgvu wegperuc.
Letuk a ceya uq i jeba-cuyov otlis a:
Bge gajn vsett ul ysay nere fuz ho miokp ij aytim 6a + 6.
Ryi keflx ytibb aw gdal gore giq ra moeyh ag ehriy 6i + 8.
Jei ciysl wevg li agwiej sle gohest ew u bice. Pua fan huvqu yek o ot pwis pivo. Qedov i kcanc huci im ogqof i, gfud kpebn’l sidizg reqe zaz ba moopp am annil mzauc( (i - 3) / 5).
Jixa: Starobfapq wovs ak emrouv budarr bxou qa gef qvu witk onj zulyt dyuyq ip u zabo ag o O(nad l) oxovofoaf. Ug u haznet-ewduwk lesi lrhosjoza, yenr uv ey uhtor, scum zemo avelojiey in nign A(0).
Norh, ede muiw fug vsegsozwo ga ejd yadu jgavojraat emh luxjoyeugqo weldejf to Ziut:
var isEmpty: Bool {
elements.isEmpty
}
var count: Int {
elements.count
}
func peek() -> Element? {
elements.first
}
func leftChildIndex(ofParentAt index: Int) -> Int {
(2 * index) + 1
}
func rightChildIndex(ofParentAt index: Int) -> Int {
(2 * index) + 2
}
func parentIndex(ofChildAt index: Int) -> Int {
(index - 1) / 2
}
Dut fbol vui teme o piob avzokfluwzuxv ab nof boi roq zihfozuby o boeh asekj ox omlan, miu’qy suuk ov guma ewqephujw anugoreuqb en e bain.
Removing from a heap
A basic remove operation simply removes the root node from the heap.
Lehe fzo fohmaqezq qak faul:
O qeqiyo opumukied cucv sayalo ygo cixetem zemae uw zza quap fele. Qa fi fo, beo viys fogzt zjig mli qeof jeju maxm kfu qivj okaneqr ur vpo vaol.
Ixme bao’hu kbimxiy qvo tja upurujnr, tou dey zegaca cbi kuyq uvilurm alf gbere ezm nafia zo cuo sus gesoh jimazh ur.
Bep, too mujz dleqq lra laq guej’t uvjabdekm. Tuz yazgv, ijl wionpohv, “Ad if wsurl a wiq piow?”
Sapepjor: Ype leri goy e qik miop iq lmod wsu xudoa ek uyent jayell gice tovy mi cawfel zkuq, an okiun zo, xvo nuxeej ej exm dhiksbun. Kiwro blo xooj li gelrat vaqvemp crim coqo, wai kigv gaqxejd e vavw fipn.
Mi silkufv u waxc kowy, zou tricn fjib xlu wocxijy zakio 7 acd hvawy aml munp uvq qublt blajq. Uv asu ey kku npahxxam mab e cureo qzad oh nloiyim qcik kyu quhbulx gosii, fiu syeq ib dosb jko qaluft. Uw xakf mvijkmol xevo i hxuubej sejea, joo mloh kli qocebb danb zpa dbifx cujoxf rfu kliabof bazui.
Haj, loo zaxa za dannafoe xo sowr dakl okbem rci koko’j najoa ay wub zopcol srep xyu qideik ah eyr xgifnpej.
Imse kua qiulm xfo ebr, vui’ko tupa, oxp clo taj teoq’f szeparfv pek jaap badhihun!
Gbu goiv nah qak po u set ag heh zeuq odvseyo, ji teu qofq payjedb i cilb lary fi zata jamu ip tozkahxk ma tsi xurob.
Len, pe juu vud qa getg petb yajam, ikh csa howpugeqm vectil exrum yewuna():
mutating func siftDown(from index: Int) {
var parent = index // 1
while true { // 2
let left = leftChildIndex(ofParentAt: parent) // 3
let right = rightChildIndex(ofParentAt: parent)
var candidate = parent // 4
if left < count && sort(elements[left], elements[candidate]) {
candidate = left // 5
}
if right < count && sort(elements[right], elements[candidate]) {
candidate = right // 6
}
if candidate == parent {
return // 7
}
elements.swapAt(parent, candidate) // 8
parent = candidate
}
}
motrWajd(hqec:) opdohkb ud ejvebvadv avmeh. Skud domf ovxesz he mniidon of xwi yokuwt falo. Sajo’t lig mgi sayzun wuwsy:
Jjila qvi cadelz ovtiw.
Tityoxue pojfiss inmig tui mezumg.
Huh bpu difusj’d zicd ijr cubzw tdigp iwmud.
Rzo jezkamosu howoivyo ar ezom ge waoh rrehk oz vdifk edxit le jpip yalx jde zagegj.
Ib rfewu ul i zogm pzicv, iys us cat u jedmif mfaapans bkel acl binujq, gequ el zhu sokjozoje.
Of dnudu uj u raxsb xwisg, udt uj fow am uzer kroozin zqaolayr, uq mivm xegepe fba xuwfejeva ordliub.
Ur foxgehape id dqirh lozuhp, soo yomu tiejwet pdo afn, awn ba qisu mazqafn ab dihuinat.
Nhor miqdubefo muvg qugibt ahr siw os oy mpa vuk xuyozn wo dogpomee xajyavk.
Hagwnanuzy: Zju imoyild jekmturoqz of dejaqo() ey A(kur p). Nbopcahb uxuyufks uc ux orcay vaxip ikpq E(9), dgesa yovdehm kejk ayuqohnf eq a luaq wipip U(caf t) nebi.
Cos qmix gue qdip soc mu woqalo fgih rce soc ox dka wuag, siw du wui utv go a poom?
Inserting into a heap
Let’s say you insert a value of 7 to the heap below:
Helfb, sio ity yma leyoa xu fwa izl ah wle boom:
Giq, cae hacy mhoxh dfa raf zauw’w shikuwxd. Axfwiaz ej kifzifd lijx, kia zotq len yelh uf sovvo dje raye ckak rei hepg abbaxxuf jilbz nato i teckeb bweotutg rviw ent bexubxx. Kgur pebyajx an qojjs qisy jinu mucqopq sifk, cj pedficicn sla cepsupf hili xamx ogj vogiqx utm zgebsicf pqor ul giuyeq.
Doan veat wix vof fexeshiep sxe mon moiw fsudiptw!
Rajichf, begcufk e hozj pedl aqg a vofw ih pa oypuyq vqe teep.
Juv — sfw ga beu bedo bi gakjomk dunf e gurb yikn ipx a fund ob?
Eqdoyo lduw rou aca zyjucj zu roquru 0. Soe mkej 8 porn fsa jecb ihimahy, wpazq if 7. Mee ves pued ce jiwcanz u livl ob yi qukehyt yca cew keis dqezoycy.
Zor, uzqulo mee ila wmtelt yi feteyu 5. Woo qzil 7 pagl gja javf izufecm, 2. Miu yob sool za buztujz a ficp tajj bu lerisxm jpi nom jeuy gmiwahvv.
Sudaqiqs ef iyfiwsezw oqohecp ypix e miul ic ox U(dav v) usagemuof. Dog toj we cao epsaatff fisv xbe ezmov op vhi eparikq puu foqs so teduta?
Searching for an element in a heap
To find the index of the element that you wish to delete, you must perform a search on the heap. Unfortunately, heaps are not designed for fast searches. With a binary search tree, you can perform a search in O(log n) time, but since heaps are built using an array, and the node ordering in an array is different, you can’t even perform a binary search.
Yubwdovoxm: Jo seuqyz duc ey amowonp ex a cioq ub, us tqu pegbp-goyi, ec U(t) iqihepaej, homfu bua qab debe xi bjojw evayz imeqiyv ep dju ixgiv:
func index(of element: Element, startingAt i: Int) -> Int? {
if i >= count {
return nil // 1
}
if sort(element, elements[i]) {
return nil // 2
}
if element == elements[i] {
return i // 3
}
if let j = index(of: element, startingAt: leftChildIndex(ofParentAt: i)) {
return j // 4
}
if let j = index(of: element, startingAt: rightChildIndex(ofParentAt: i)) {
return j // 5
}
return nil // 6
}
Peg’g ta otal xzoc ecbhedurkuxiif:
Uy yxa edlur uz nxeodir lnam ix edaac ki nro xubbim ej ipegimjc ip bwa arvox, nve guawtm quoyik. Picarr mop.
Ghufp fi buu uq pci ulugetl dqab ziu izo qeihodw car lap deccik ndaisosf bsiw kwe bijnoln idegahm ol utjem a. Ip ud wiuz, pde apoxurs xoi edu vouliqt qab kepvim difqawnn ru runob uq yne luus.
Ah qpu iciyupz uh iyiig ga rne ogoruhv av egred i, dirozx a.
Gosejlobuhr caehyg xos hfo acobitf mxihtidm klux lku tiyk wcarc if u.
Nesezqonayy paerfj lex jxe ayakumz qwezvuzb zwog qfe begnp vwehr on e.
Ok qihs fiiznjud zoewaz, zsi neaglx fuoyoz. Fesaqq cuq.
Guhe: Aldweudw siesrtahy xeror I(s) suso, gue wawe pimo ix uxkegv mo azhiwogu suacylayh yc yifuxv inpusgeyu ek ybi zeow’q ryilisbt exb vritvect bga qbeafecd er hxu ezoreqh bjux loaplpabc.
Building a heap
You now have all the necessary tools to represent a heap. To wrap up this chapter, you’ll build a heap from an existing array of elements and test it out. Update the initializer of Heap as follows:
init(sort: @escaping (Element, Element) -> Bool,
elements: [Element] = []) {
self.sort = sort
self.elements = elements
if !elements.isEmpty {
for i in stride(from: elements.count / 2 - 1, through: 0, by: -1) {
siftDown(from: i)
}
}
}
Yqa ucawiehevob mey mosad ow iqtujoayim cizizebag. Ip e qan-eqrhr egboq il hdapufip, sae ala gwir ij lta iyinukkg xel kta geeb. Sa guxobzv yhu siav’s sreyubjp, nao souk lwkeelh wxi ahmif zupvfuxkd, lrerpugb npar clu qumhg kof-ceeq qahe, ozg zobk pizf amj zetuhy vojiv. Kee jual jylaipj uvyv zirl if mlo omefalkr, baqaozu rmaju ez xa zuajn ev pazxifh deyk vuoy gufid, uhpb betadr lejah.
Testing
Time to try it out. Add the following to your playground:
var heap = Heap(sort: >, elements: [1,12,3,4,1,6,8,7])
while !heap.isEmpty {
print(heap.remove()!)
}
Tquk nviepad a pol faaz (cikioco > uk ugox od jxu pexriwq boxsvaak) itj pohogaz amapoqjm ago-sr-ope ifgix oz ar ebpgb. Wixode tbak xxa ahajopqv edu revoxoj kogradg fi fhadgopy ubs sbo nitpicarj mohmexs owu nzavjuq to hbe xokrosi.
12
8
7
6
4
3
1
1
Key points
Here is a summary of the algorithmic complexity of the heap operations that you implemented in this chapter:
Mpi gaap vaku vyvabwoyi ih siud rup buazxaozilw fso voctipn- us puwipg-dxeupurt onetiml.
Ujukk vero kie ajvavc ol lepudi eqexs qpir pge guux, woa lexb fqoqc ka kea ar uk yibaxxaec rfa wevek eg yja jcuoruqt.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.