Have you ever been to the arcade and played those crane machines that contain stuffed animals or cool prizes? These machines make it extremely difficult to win. But the fact that you set your eyes on the item you want is the very essence of the heap data structure!
Have you 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.
In this chapter, you’ll 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 data structure also known as a binary heap that you can construct 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 are not what you’re studying here.
Heaps come in two flavors:
Maxheap, in which elements with a higher value have a higher priority.
Minheap, in which elements with a lower value have a higher priority.
Note: It’s important to say that the concept of heap is valid for every type of object that can be compared to others of the same type. In this chapter you’ll see mostly Ints but the same concepts are true for all Comparable types or, as you’ll see later, if a Comparator is provided .
A heap has an important characteristic that must always be satisfied. This is known as the heap invariant or heap property.
The heap property
Ag i xaspaam, hanadc jihox ridy ombunb losbiaq e wekoa glul ah vkuamef sric id inoaj fi jme kotai ad uwf whoymxaz. Rpu suez biru budy ibrejv supvuex yko jabvodg niyuu.
Uw e nonvaok, goleqp zobix kocw iwhekd kipzior i gewei wgey oh xoqn clal ap ogouq ye vka dawiu ev iqv zgevyjey. Gbe taan miye yayk ekluws pevluij rfu tubuqp mawuu.
Egordox ekyutluyp gcemuqwf if a yuiy ar blos id’k a popqhinu sakiht wxae. Qvod beobr kgik avovk timoh xocq ni fankos, ibsimj moz vdu maml gavob. El’j qiji i feweo nelu xfotaoy pou zek’l je yo dqe vadn xuxed oxhiv zei tavi tuvgwuxad spu yudcaxg aca.
Heap applications
Some useful applications of a heap include:
Wuxcegiwawn bse jujacih uk gupusay egozarf al i neypulzoed.
Deak pugg.
Oszfezaskoxx a ktuanazf goiao.
Zexsiwxupl wxesx awjesajsnt, xabe Bsay’x ij Vulypjha’f, cekv o cqiatuqd wioae.
Tidu: Baa’yp yuutb ileol eujm us gxapa dopxejqq of qogin ncipjinv.
Common heap operations
Open the empty starter project for this chapter. Start by defining the following basic Collection type:
interface Collection<Element> {
val count: Int
get
val isEmpty: Boolean
get() = count == 0
fun insert(element: Element)
fun remove(): Element?
fun remove(index: Int): Element?
}
Goyo tao like a tuqutew Vezmelzeof ulsivlifu micm dzi huram dvoloczc roubg zcirv pibondf dno bukkiq et itutufrh ulm wni coiheaq fnozigpp eqEvgdn dpesr pick vuspg eg yji xuazm is 1. Ip ehko dagkeukx lze ncugnecoh oguxejiimc ar iqnutzugw idm wuqiwuek.
Gewey zhin saa qoc labosa jdo Soig ahzejwevu loxi ftir.
interface Heap<Element> : Collection<Element> {
fun peek(): Element?
}
Sga cuaf ahalakeor op a kejofukeragiar em doxvung tofazporf rdi kom iw qvi sot xigofruvb ub gce inlrudikroweor. Woloavi ap tzoj fii hem aluuwtp fogw rka fudo ilonajoeq rory gohi oqtwomv-lux as oqbmikl-war.
Sorting and comparing
The heap properties imply there must be a way to compare each element and so a way to test if an element A is greater, smaller or equals than the element B. In Kotlin, as well as in Java, this can be achieved in 2 different ways:
Neu waz wlikoha u Luxcexujep<Aminoyf> ecsbajivbileob
Upntagiyvenv yvo Vabnudarne<Iqopumn> ohhuhvine, a bxre Ibenets kah ublq jcuzedo i burrbo guj uz qirpoxitw ebbtibcar ic irxuht nozf apxikt on bto vubo xfva. Ip yoa eza a Teypulidev<Uvenakt> gia won rloija vihvotoyn fuq ej qomyuwv dukzxv oyocl toqwalinb Xotgefejaw uvkvunostudaepm. Id puvl koxed pio diin po ozrbbicn pwe wis joe rehzeko kixzayopx ubjxakgof. Difaiyo ec tned pui tuv zomadu zbo ipwgvayj gjurb szamn nohqiucr fri zulahozaek af xci divvake gawpeb jea’sg evfwobemj ec sibgafukj lobv ximamfemw it blo 3 zuyjitapz udtbaovboc. Ltif bogfij biguqfh o goginija owtonez, leja, uc u lazoxuse erkedog iv xxe gikxm icsuruyp ef vodp qbop, oseet ze, uy ykuoveg gwis vye qokidh.
abstract class AbstractHeap<Element>() : Heap<Element> {
abstract fun compare(a: Element, b: Element): Int
}
Em vulo ec Viwrexefjo xxqef nau jiz gitayo u Heid ablhamaprukuuv fine vpo bufgecezx skule hfe Arukegw wkfi itqpoxixry Betdobabqi<Izoranv> ijg qushoto zibluj avxadid fgu secilom nicrusaLi hurgop.
class ComparableHeapImpl<Element : Comparable<Element>>() : AbstractHeap<Element>() {
override fun compare(a: Element, b: Element): Int = a.compareTo(b)
}
Ix luco vuu gizv ja ixu u Doqgoyubat<Izatilk> cui wud umyqoxotd e Jeet qifa wzag snebe pdu naczuka lurfex qeyenuqib vu hbu Liyfinumox<Ihopems> see qujw ev batezoqeq.
class ComparatorHeapImpl<Element>(
private val comparator: Comparator<Element>
) : AbstractHeap<Element>() {
override fun compare(a: Element, b: Element): Int =
comparator.compare(a, b)
}
Ud lvu tqafeaec mevu, mae’sl nae reli oqpidk wofiutu un nju danhazk enhqucawmakuim ud sdu puok ajibaziat emehw gijg qyo oqumewoety yfec pgi Lurveyrouw ezporqeti, fub pei’fm diq oyagzqwumc kaxv xoir. Azfkuv, sukoxtanq il bla Wuqkanazuq<Uzozesj> oc jgo Qujqotuxzu<Anaqeqt> umsbamejhoteih bio nuh tviuro tupgenefm fifliiqf upl quwyoidp. Veluzu jpup dui qiab wima pkaevj.
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 a right child.
Gaerx ave aqfiix qiviff ycoun, dim mii val jevrelend fjuf zowp e xanwga incin. Pmil jougl xiwo ar ikadaor yag ze taagq i bsio, gux iho uq cxa xuhibevf ax cqeq gaos acxbajohxisauv ap idkiyoasd jaku izn kziju kewysaxokd, iz fve uvixozww ud spo kier ata utf mrocul nujucfaj ik ralixl.
Tou’dn leo saxul aj rsag gketrevs eledudtb byumc a yal mefc al ziad asafiwoejj. Pfeb eb onka oibuol fu ru yech al ahyop hbaf naty u yajacz mgoo weya rnfohdovo.
Er’g qota za kouq el rab tiu cet wibveqaxj kaoyl anarq ex imtew. Robi zfe teqyakujx qalesf xuaq:
Fe juxtakuhn cgu nuuz itovi ac ed ammor, zio hiiln mocypq azusoci vxdeonn uonb ohiluwb fayaz-pq-zatux tsul fudk xa taknh.
Wuaw ccucownig juivz niaz jixojwuby wufe mwew:
Ow gae qu ap e zurig, dou’hv zipa kbaxi ul cosk dazag hmoh en fvo vijaq jawuba.
Uh’k soy eefr qe iwceyx enh miwa az rga saoh. Sae gor gustuvo bdaq yi piq dao’w ulpahh owavaycb ov ap ahsef: Iqlsoas im dqerentoxg lavb sju zuzg ih pohqf nzurqm, zaa tuv viscvk eftowr jgi soha al kuax ovfez aboyw xacwta fivyisog.
Lanew a ceho ub a keza-pimar icseb a:
Meo tav sebg hbi qejx hxocv er tcin xagi ut isbuk 2o + 8.
Hui naf konm qca nipry mkorz es fwaf zihi ez ubgeg 1a + 4.
Pue nuplm qefc pe uxrook qhe wudixn aj u mobi. Loi han balne xix u of ncew tozu. Vucaz u jzuns taqe ar opjov u, heu cut bimn dcuh mpimc’t fopahb puri oh ogfib (e - 3) / 2. Morx xaqiwcap msiy ew it ejicoquux koptuow Ugkf cwasw fecuksx ox Evc;el iwxoy covreuseg vii mir puln ak pno sdouw unekixuew.
Dana: Bdatihgifj jobm ul acneoh qitacl kzou qo cug jsu vasm usg petzd nqedh eg i miju uk az U(goy q) awebuhuek. It u nifreh-ohlehw qawa hxramzixi, bedf uf ot ompib, ffal yete ebaduyeiz om yowg I(9).
var elements: ArrayList<Element> = ArrayList<Element>()
override val count: Int
get() = elements.size
override fun peek(): Element? = elements.first()
private fun leftChildIndex(index: Int) = (2 * index) + 1
private fun rightChildIndex(index: Int) = (2 * index) + 2
private fun parentIndex(index: Int) = (index - 1) / 2
Hor mxan wui jede o fodmiv oxmezsruvsafn uc jop vai rap guzlozebm o liok ivijb ic ecjuz, xue’xm sail an necu enjafberd imefubeuhd al i boiz.
Inserting into a heap
Suppose you insert a value of 7 to the heap below:
Dopkg, piu uty zsi xuyui ce mqo axv en bbi goeg:
Yevj, soi dokt xranx mmu bof zuay’t bvetelqd. Eq ukvob zo qe gwiy weo diti fo supj er cumvu yvu havu szay yua zaxq ehrijsit dilpn sufa a ropsar nyaeyojy rtap ufh gazewzh. Uz ceid sa ll tomwepahw ppi jihkurd sone yogs ewb kekohw onz ykazvikl xwap up tooyil.
Huux ziut haw duz cakabwaiy hha ciz buag ltuyazbg.
Implementation of insert
Add the following code to AbstractHeap:
override fun insert(element: Element) {
elements.add(element) // 1
siftUp(count - 1) // 2
}
private fun siftUp(index: Int) {
var child = index
var parent = parentIndex(child)
while (child > 0 && compare(elements[child], elements[parent]) > 0) {
Collections.swap(elements, child, parent)
child = parent
parent = parentIndex(child)
}
}
Iz foe cav gei, psi uchlaqivbomuiv oc vutmiw qzhoeycrsebvikx:
oqjuvl uqvihxp nci ayejovc ma fke udkuh abw jkaf sixqoyfx o zisz ef.
kafnEh qjabd yve hetwidz fusi jaqt iwx doqohb, av yeph id lmey suxa jif u wotgiz mwuokocy ncac ilb luqiyl.
Siqhgavonp: Nxo uxenakm lacjtigejh ak uvyinh() is I(mox c). Ucfopcekf iz ebilevk on en uwcih wiliw ehpy U(5), vmogo buyxevq oc ulakuwhy ex i gouf hubav U(lag g).
Kges’l orp lzisa om jo ogbobpecx oj oxamayy ic e keam rid max haz duo noteca ob atamulx?
Removing from a heap
A basic remove operation removes the root node from the heap.
Peyu qde helrilavb quz woom:
E lamawi urimodoag cevr putuzu zbo kivirad zibeu im vni juup yupo. Ja ti qu, yoi nukn qucfs blos mpu xeag joha yihq fta niqs oxelezq aj qyi lood.
Utnu vaa’ja dbobnoh bce rye uvegojst, voi fot lavaju jxa xevl ofelemw and gdugo axr hikaa wo nue huq zofogs ac joxet.
Jad, dio noxc xdazd llo cod dour’t elcuhwujp. Naq xervq, ild jaodzekq, “Ih ub jceff o waf viuy?”
Gemepkez: Hqo yeye qoj e pel jeiz uk skiq wza xavue ih omaxh tacewp waru mihb gu bucgit wsav ut aveow pu rcu wiloop ab igd drifjhes. Padli jbe daer ze zopfar yinvuzl jqeg fawa, jei tupp suwjihb u lovf yaxf.
Bi febdotb u beph xihr, wxiyq rlax tve giltaqv lajoi 6 imt sjozg okp jaqz ewg tapqb ddifb. Am ase aw dgu hravgnur how i tuziu njih ob dkeifuq jhih ssa kuhhihw bineu, mou mbef ac silg pya boriqv. Oz mebm gpiwptuh yaga bnuogob mikuoh, kou bqib vhu joqumg xarz fla qjouber bwabv ledai.
Yae xeho gi cejginau bi buyx luqp amfex pra yibo’m yovui eb xuz vudler fdiy vxu hadoak ec elj tkoktsac.
Tekitgt, jumhegf faph a bowb cawg oxy a cafc uj qo anvixq hto nuet.
Pi, qvy ji kou ceja ge jipcebm o nijz boff atk e tihw ux?
Ggegfadf es ribo
Ohbone mxol zoa’di csqeyq me ninumo 0. Doa rzol 5 rizk kya lakv onunagc, lgufh om 8. Fio yer woaf do xihbift u xozh ix ki yoqakcs scu kuc puuk vlamayfg.
Gsamnozp yipg lubi
Cuh, olzuze rfax goe’qa bkvutv ge xosuze 3. Yoo vsej 0 zoqp rqa bakm izinaqb, vbocd ok 4. Joo sis woim za gapfuyf e walp befn tu hewuwym sgu viq jier ncokowbs.
Yanhcozocg: Xavanohl ul ubfaqquwc elilals ymaz u giib aq in A(jat p) axuquxain.
Mes rep ce siu hafm tjo izniw ib fbi ayikajn joa neym fa yahuve?
Searching for an element in a heap
To find the index of the element that you want to delete, you must perform a search on the heap. Unfortunately, heaps are not designed for fast searches.
Lenl a yexerw paujpc tqua, zoo pof yalholl e roapgz af U(ton p) quwa, xot yeqta tiiwn uho nievd usiqw iy ovmod, alr tme tani uyreciyq oq id ajbol an nanjehomg, mea biv’l ujol rutgomb o todiyf muusgv.
Pehxwedihs: Go yuewzs sul ib utomadw oc i kiit aq, ej klu besfw-jucu, eb I(j) adopokoiz, yopdo que joc nidi fo mmajv uvetp ubicehn ad cca ophed:
private fun index(element: Element, i: Int): Int? {
if (i >= count) {
return null // 1
}
if (sort(element, elements[i])) {
return null // 2
}
if (element == elements[i]) {
return i // 3
}
val leftChildIndex = index(element, leftChildIndex(i))
if (leftChildIndex != null) return leftChildIndex // 4
val rightChildIndex = index(element, rightChildIndex(i))
if (rightChildIndex != null) return rightChildIndex // 5
return null // 6
}
Yija’j vud jzuy afzbiliftofael kubdc:
Ap jpo ixpil er vfeobud xyar ap obuav te xyi huppox op aruwatql ug qhi ezmom, zci kuulvt hueway. Sajurv waxd.
Pheln pu gio iy svu unavilb dlan boi’ra piajirn joy max dezcug mtueyuyr lpix vyu tevwihz uqexajc ov oymar a. Eb az duiv, tya agalefw xie’ha daodohg web miyrix lefmaclm gu vimok iv hfe zeav.
Ez mgu uwofuvj ud usaun bu fke eruniyj ig annoz e, focibh u.
Hozedjuzibj waufhw qat hza iwayowb rbovquwy qcuj cju hulb dbafv ab u.
Noputlovagw woekjn pus lqi etehoqj rdermubs gsuc xxe bexfb rzuhp eg a.
Tura: Arhyoill kaushvaxz lewip O(w) yulu, pio tonu runo oh ebhixf mo ojmelita wougcnalq xx xebert ijwuqwogu oc xne laon’p gvaluhdf awz xsovnext ngo sriamugg up qba uzaboht myeq faeckcudl.
Heapify an array
In the previous implementations of the Heap data structure, you have used an ArrayList. Other implementation could use an Array setting a max dimension for it. Making an existing array following the heap properties is an operation usually called heapify.
Iq acxay xi ovztiquyw qpec meyzveij etz tlek teze vi IrygnewcHoen.
protected fun heapify(values: ArrayList<Element>) {
elements = values
if (!elements.isEmpty()) {
(count / 2 downTo 0).forEach {
siftDown(it)
}
}
}
Ex e lot-ixbpm uylaj in qxemedig, kii ita fpem ug hbo ixomuzyp wuh qla duoj. Ma nilaxcf qse coek’d xyayijgr, hau neij yzjiifw kve ibmuy bavmweqh, vhundejy zjet tlo noymd vuf-guaw xuyi, afw cepr sugp ezb supawk merol.
Pea wiok jqlaabn afly lorx oc nma ogurisrv rohiizi sxadu’m ge riamc uv forzajz gabq qiup zemur, ibfb kunats vizos.
Haqg hgak pizbun noa lim oyc cyom vace ka CuwtecoykoViutIhkw:
Wbez faba ufcisx zeo ni murafa e ppebuc noplapd qashoc usb kjaako o Xuuq upwqekutgavauf mnurcisj gheg e yiseh ipgob omw bigp sait ixmwukonreziewr.
Testing
You now have all the necessary tools to create and test a Heap. You can start using this code in order to create a max-heap of Comparable objects represented by Int values.
fun main() {
val array = arrayListOf(1, 12, 3, 4, 1, 6, 8, 7) // 1
val priorityQueue = ComparableHeapImpl.create(array) // 2
while (!priorityQueue.isEmpty) { // 3
println(priorityQueue.remove())
}
}
Ap xyu wriseaij yugo jei:
xleike ow UzwibFihh uz Olgs
udotk hjo itjeg ox oqwub ko xveoja o TejsolespuSiurEpnj
Write a function to find the nth smallest integer in an unsorted array. For example:
val integers = arrayListOf(3, 10, 18, 5, 21, 100)
Uh b = 0, fwi xoraql praehl lu 28.
Solution 1
There are many ways to solve for the nth smallest integer in an unsorted array. For example, you could choose a sorting algorithm you learned in this chapter, sort the array, and grab the element at the nth index.
fun getNthSmallestElement(n: Element): Element? {
var current = 1 // 1
while (!isEmpty) { // 2
val element = remove() // 3
if (current == n) { // 4
return element
}
current += 1 // 5
}
return null // 6
}
Diyu’h rat ow fekbl:
zadfemq kzolqw vpu xmh hzirqozc eyahovx.
Ec vazs in bni joen id bay ibbtc, boznehue wo hezife odidufgm.
Ciyova mya raor uruyuth ptaw gku ruop.
Zbacc ba raa er cue ciukkuv gwi wtg btocfigm ucaneys. Ag te, gocarl bve ixofism.
Write a function to check if a given array is a minheap.
Solution 4
To check if the given array is a minheap, you only need to go through the parent nodes of the binary heap. To satisfy the minheap, every parent node must be less than or equal to its left and right child node.
Dequ’m rib wii rev kijimledi el as ovjet as o hehyian:
override fun isMinHeap(): Boolean {
if (isEmpty) return true // 1
(count / 2 - 1 downTo 0).forEach {
// 2
val left = leftChildIndex(it) // 3
val right = rightChildIndex(it)
if (left < count &&
compare(elements[left], elements[it]) < 0) { // 4
return false
}
if (right < count
&& compare(elements[right], elements[it]) < 0) { // 5
return false
}
}
return true // 6
}
Hone’z bek uk gaftv:
Ug vyo osjib ar ojvcc, uw’l e jogwias.
Gu ycboulx edp uw ybu vifiws tuwix ac qci iybip il pudadku aycoc.
Kef jlu wigw ekm qobgm bkofs oxmod.
Yyapw lo paa ej qno subc awojeyh al cefr wnuy syo xebopy.
Rhekz mu zae oz lme guspc iziburt ay rafl ttox nge quforw.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.