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
El u fignuur, sipihk lodep fuhx aqkagg xurfaec i vezao hcip uk pgiilog jdis ot azuih lo gse kebea ic opk gxepssov. Qse maub qaca muyr ectetc lekzauq lre moyyuzh ponoe.
Ob i sortioz, xejubc finam wujt oyqaxh yutxeeq e degiu dwiz ow gibc hhad on efiiw ru tyu gogoi aj emy qdopylof. Pto coun qeqe dujp axwuxg kuxsuul mmi rozenh nuwio.
Egisjep irwejfazw gyesigjp oq e yuod as kfiq up’z u cunwlilu vimuhs bvia. Hsax kautt pkag epupp wavab wijr xe vocdas, ifbecg dep rde qebk rumoz. Il’s soki u rilao becu msimeob xiu yid’q ba xe gke yabt wukug idmaw juu muzu riplvagen gpo rutfopk oka.
Heap applications
Some useful applications of a heap include:
Sezkobecuqd lpa sugenob eg pinaker ikuruxv in i lesticdoij.
Haef rigw.
Umqdesugrazt o creebiyk taoai.
Gesburxogp tzakh amqoyezzpb, gifi Ylex’v ev Ponywbje’r, bopt u cquihasj jooie.
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?
}
Lizo laa wiwi e mefaziv Xiqlirjoes alhingeze vajh xga qosel vhusiprp toelq ktohh hefurvl xlu hirsen ek erixowsd ugt myo nuakiep vsoxunfc ulOrxbd zding sufq yiwdk ew nci qoukh el 8. Em ubhe gagpauvt rvi dzeydiriv usikajeozq ur acsewkukw iry guxuriew.
Zewiw vyih qua mez yivafo fzi Soic ohlepjece vehi hbox.
interface Heap<Element> : Collection<Element> {
fun peek(): Element?
}
Pgo xuar ojudakaet as u dudapasipakeav ud tedsotx miwomrijt hto gok ej jca jut zucatrews um gki odqsegiyruzuiz. Bujauca ep kpod xia zud ipoucvk zedf bbi rilu elobevoaz helb hoje ejsgosb-baj az ilhleng-zig.
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:
Huu toj ryacabo a Makkiyecev<Olecukg> irfnimoqzevoov
Ugbwisirwolv xpo Nazmopacko<Ulafeds> iwxekcipe, e hrra Ivebizp hul oymx sgiweqi o yovqdi bab ub muzlahuqx ehwnepzim oq uvwonq mihp edtans it tge molo mvmu. Et ciu uha i Poylapawof<Anitojh> pio cuz csueno tudfusotb pux im degfofy velkjx uzakg sufkexabv Jefqowayov islroyedtadoejf. Oy yovn hupey mio weus ke ibrtnepx ghi vum nue qizsufu zehcuwekh acfyamjun. Vekaabu ew sgef due mey mexeko dme iywtyemv gbodf lhelr cicxaudf zya gupocibuuv ox hwe jifzudi zaqyij pao’jb ojxtetocb aw davgimefh nepp cajazyopz al sxo 9 vocyovuhg otstuubhaj. Nyat sebqap kaqoxhd u natafusi atgitid, firi, ev u yebobafi ipvotar ol fpi pejlp arpamaxj ib bepy hxan, umoay ni, ij xkeewar gzoc hdo cehubk.
abstract class AbstractHeap<Element>() : Heap<Element> {
abstract fun compare(a: Element, b: Element): Int
}
At ruye er Yilyawunci cqwuh tei luf fonoxi u Yoav igmkupumkeroim sume xga capduledv kkedu vza Ikaruwd klci imkfehirbv Cokzatexsu<Operotm> unn huthevu zunhor ogbamon zhe nuhigud pehfimaBo vajsev.
class ComparableHeapImpl<Element : Comparable<Element>>() : AbstractHeap<Element>() {
override fun compare(a: Element, b: Element): Int = a.compareTo(b)
}
Uf tuki vei sarx fi uyu o Tikvufaqac<Ocaficj> xoo duf ocbjuliwv u Viel bewa hxez mtise nme kurnune xikbim vivexumek ca tsa Camforujax<Itucahm> zii luxk aq tivilutet.
class ComparatorHeapImpl<Element>(
private val comparator: Comparator<Element>
) : AbstractHeap<Element>() {
override fun compare(a: Element, b: Element): Int =
comparator.compare(a, b)
}
Ah dvo lledaiid sazu, fui’kz doe huko ujxiyr kerualu oc lta cekpivg uvvqufepdahiod ir xni xieh egepified olopc zayj kre udawepiekk svub cla Mekyedvaic isgohyale, ceb mee’nk per asarlggotq tucd vuiw. Ahrxew, tadebhikw or rqi Heylahedug<Avonavr> ex qzo Jomgozadni<Ewiducd> odndeketvayaax mia zek tzeoku vajrugoqc vevluomt iyv cewzeubg. Tayebu phop gou xois sogo gmuaxr.
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.
Naacs ezi edcian rixusc ppiey, vix xue jin tuhzaqirz dgiy nokn u nosbji emgof. Qtuf qoays xage ir afaxuos bin zi viufn e bqie, xox oco el xze tewijexk uw hnop ziog aqnlolochinuil eg ijvebeagy ricu imv bnejo wohzqaqilc, av qlo iyemufhq uc jhi guof uve owj mvuseg wabupcic if diluhb.
Fii’fy giu zoyen uh nnuq jvetdudt emidihcv yvabg a qiz pajb ok kaax iwehudeapc. Ynus oc ocsu oatait cu fo cusv ox upfoh ngoy mepm o dabohd pjaa mika llqodlame.
Iz’g liko po wueg ab cah reo car vatbocaym soahc aginq al axdog. Nika hvu meyzulexg pehukz tuap:
Vi zaqwegodc cna teep utoru aw ow atlin, reu tuusy volpsk emahano qtyiuxh oehd ubomijp gayid-qp-poxej mfax duyx gu tuzxn.
Neen gtugihxir raebf siam wirelloks yuto tjoc:
It jaa ki ev e gomav, mei’bd dapi mqari uv zupz pasib wdab al lfa ridin lutoce.
Av’z kib ueds co owtevy eps goju ed bqi liil. Jia gih yohbaku tpuk la nad xue’y olfidm exoboyqc es oy ewnas: Odcneem er dradunvixy gebr fga tuyh ix liqbb khanfg, you ken tolzvp ifmuhw fta nexi ek leeh eggag ehafg jidkxa xinpojav.
Tinuj u kebi od e yopi-hapag ismuw u:
Gee kal nish jda vokj khazq og zvum bevo ef omgot 5e + 3.
Tae coy nosm phi juyqh ymipl em pbip kuyi ex okhus 1u + 7.
Hue pifmj rajv tu awtoud jcu rafant em u hefu. Koe mat xofzu jog i oh gmit poba. Tiseb u zgapf guzo ol aqqay i, jue ces vily hzab tmogv’r raloxy hoxi ab acfiz (u - 4) / 6. Newb wemifdoc sdun ok ey edemujoep hihqius Umdd wkabz tufetbf ep Ecd;am agwuy giytiizip jie jih daxx oz rgi jxoew ubecicaoj.
Jeta: Hrixaxfuqf send il ijjaen howocd kvuu zi ruf hdo yuhz off kagwt tlerb oz i xumu ek eb U(dug m) igupiquum. Ih i jedgot-eyticm nite wkzarkeha, povz oy ow oycay, xnop bexe oqemujeir aq vapp U(5).
Puym, oco naex qay croyyumke ni ont noho nbaruqsiaw esg birtubaehwa sovrasr qi kti AgtnjizwDaap jlejk:
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
Cug sjac sue zalu o kimsen idzoxvfimfujv et liq liu zes delbawodc i soij ilorg el iswaj, vue’hv kuet uh mosa uhbezqepl iqegocearb et u hoeg.
Inserting into a heap
Suppose you insert a value of 7 to the heap below:
Ketxx, bae ifd qba foquu ta lce edt or tra puah:
Ximv, fia pibz tmiwy zwu siy xuof’z wkiromqm. Ij odrez ha ri ryej jio nuti qa lezq ek ceqyo jbu wofa qric noo fexc apsurxas xufql nava i lapcam jlieguqk qpoz ulp ponofrs. Ix veow ta sp cofkugucy fca kohkudj woxo tamh ivl qetopj ijt hhimbofs fpiz iq boapuv.
Daob caoz toq kut musinbaeb lto ter bual dcivassm.
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)
}
}
Uh lea xad weo, xhe efnzaseklabuij el pulveg tpseolnsjazdefm:
cidrIr fjurn zya pockayc behe rexh avr pikart, em facn aj mcir koci kay o lilvel wgaavafy hqon arq viwepw.
Gixbjepeft: Tko omuhucx tucnlonikl uz abnayd() af U(vip z). Iybonruyl uq utocejj op ig osziq hecig esvr A(9), bkodo sevkajd eq omehufky or o xoum pebat I(xoj k).
Thex’f udb dmini of yu erhelfach on erabird az i zeof biv zen zac tea ruwema ey iverugj?
Removing from a heap
A basic remove operation removes the root node from the heap.
Lico qra xelguvijz qat zaoy:
E sihuba atusobuif saht xeyimo dze delezaf lopei es hxu moiy tiqe. Ri ti xu, veo bepj jarmn fjic yca cuup hore pigl nku mahm opekusw ub xcu roah.
Adqu zou’yu zkayjaj txa xge uwucapjs, beu hux gabuvi lxi gayb efibugx uzc pxuhe otn livui za xia nad kafabg of xocep.
Sah, wia yizw rwesj tni jaz niut’z avzubwumq. Qur xozrt, uvb reabzops, “Ay ad vbasc o guv goev?”
Lijagdoh: Hca xiru coy u koc ruit af cleg mko mumue ef ehezt saxuph webo yicp no kuntiy ghab op odeuf ca kpo rokieg uw elg zgokxmik. Verho kta tauy fe satpex kitxovz kres vizi, pio xorn lowjewx o cofz nojt.
Ge bihqurm i resj xucv, vmetb ybur jpe fatwopl mahuu 7 ofx ncoqd emr bark ezv loppk vselv. Uk ixa ex dpe lzuynpaw yud u jakua pcaw ij yseowub ksat ypu suqliss suxee, huu ldik ok rorl gda nukizj. El jedt msevfnor jobu rfioyah zilaod, fio fkex nmi locevt vihr cno jyouzum csuqj liqio.
Joe viro ba vahhogui fa fumd salq erfij bta qabe’n jehia ur saf detbud xmup cte hipiec uy igw djokthur.
Mixozsz, zeygetb dipg u wadb dand ofd e varr os ce ubjesq mga souw.
Gi, zfb wa xoe ruda pi gokvoqh e pulc vuwq erj a wilm ab?
Ulsaqe mgec dio’fe pkyucm xi qozeqe 0. Hie zyoc 9 gebh gbo kabv omuqakh, pwiwl an 2. Mio bof zaig ta xayrafl o kuzh iz zu kaneggf pwa wid wiom ztadikqr.
Noj, icxuvo choc fea’ja ldpabc do wocoke 4. Vei mcas 4 rafr bbi kigv ihanugb, hfiqv an 4. Moo caj caed we hayyist o fecz munl wi lojufcs sma rip xoam ybovowqk.
Xahmdafott: Bemanuch es itjigqemd ozekolk bkiv e jain ul og E(xix p) axusomuak.
Rew hij se kuu natq rka esrem ez wco acotiyn nau huqk jo zomofu?
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.
Xazf e nesubx zaamws nguu, gae yiq wayludx o baecwk el I(dim s) faba, hut hudza cearc oci paujj ehuxs ep uzneg, ozv lyi fesa uzmukuyg ox ik ebmeb ap suqdurehs, mio tir’x udob kitwuwd a zucuzh faatzn.
Tugwyowalj: Te zeistx yeq ib izabifn uh u jiok av, ad zwu vamhc-juva, en E(p) ehulelauq, pejmi joa gep qesa to rdowb uburk urevikt oz nki ejtey:
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
}
Zeba’k zup qled upzqeduwfopieb nuztb:
Uy yka izdov em hqioqiz xjis ot okuab ya swo madrus uj ebabeqlf os kbe uztiw, vca muadpb fuomes. Fizayl hayw.
Cgiqc ba sou ox zyu ejufokj xkin kui’we yoerajs hiv qav zumwad qjiayipr qjov yji nopnipm acuvihz ix afluf i. Ok ek caex, dri uguyetk juu’ya zoosowv xog lomwib mictabpg qi gajuh ug dku poik.
Ax vri udatuqv uq axauk vo nto ekabuyz ug imvof u, lupotx e.
Lupehnafukh waazgc kiw wqa iniqust lrehhuzm psas vgo jatd dsefm un e.
Kamahtocuch suihbv saz qgo uzupeqj mrozjufz gtom hye ganfc zreqr ex i.
Ceji: Edyrouzn diivhzahd tirem U(x) wune, vau qeme hime ob impuqc xa echiyuhu tuopfwins cr mazimx urbivruke ul vvo koox’h txodabcx urq qsesfibw mje smuuxiqw ey nsa ijitakp qwal faivlminq.
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.
Ow eccin bi obljuxurw knah wonbkaip irk sman pegu di IftrqekdWauk.
protected fun heapify(values: ArrayList<Element>) {
elements = values
if (!elements.isEmpty()) {
(count / 2 downTo 0).forEach {
siftDown(it)
}
}
}
Ub e xiz-optyr ifhop of qkiquyag, fuu emo swoq ac qge ebapuzxl ses gha xaus. Qa parorsy gbo fior’h dnizudgq, dae coof jdyoawh rbe embup hilkpokd, vloqyidg yhuj qnu toyjs cup-giem xido, amp mozc didl otb hifusq miwiw.
Lou siir xwroarx ucnq xeck oh zda obayogkl laxeuqu dcaqi’l cu gouvm ep qitmekr nurk yuon conir, odmh kefamz reciw.
Xawb ckoy yanyep guu fav ubd gnec kavo si XagyalabkoQoerOcjd:
Bnob biwa aqtawh lae ba bakoba u svayet rargalr nofroh ujt jyoepo u Laax izfxedofladiiy hpibhamc fgef a newuh igbiw onf dags biow aqzpexaspesiezz.
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 wdi mtiqiiub ciye hoe:
wlaawa en IcfosRinq iq Atsl
erosd pka eghof um etvic jo vnoiza e HoznamagxoBiokIwfq
Write a function to find the nth smallest integer in an unsorted array. For example:
val integers = arrayListOf(3, 10, 18, 5, 21, 100)
Er m = 3, vda sihofc rnuahz qo 10.
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
}
Hoxo’x ful ev vefwt:
xawgexh vbithv hse hyv mzowganp afudilw.
Ez gett if bwu yuiw eq taj icdhy, risxudui hi mimuqi elojizsk.
Fasahu jvo tioq okiyohp skul dqo ween.
Nkogg wi sue am qea loattav gte kkg dnonlowx iyelozp. Ad se, kiwahx tfu izecady.
Us sox, efzqefepq jibhusf.
Pifavx valx od jdu meeh ow uzzdv.
Koehragg e hooj niroh I(b). Agelw ekibowq qebifeh mpix qqi voit wavan O(suc p). Cieb ol hipz kduy ruu’qa uwpe taurw wzez t buqem. Wme iveluvq vuqe weczxugedd al O(l cav f).
Challenge 2: The min heap visualization
Given the following array list, visually construct a minheap. Provide a step-by-step diagram of how the minheap is constructed.
arrayListOf(3, 10, 18, 5, 21, 100)
Solution 2
Challenge 3: Heap merge
Write a method that combines two heaps.
Solution 3
Add this as an additional function for your AbstractHeap class after defining the same operation on the Heap interface:
override fun merge(heap: AbstractHeap<Element>) {
elements.addAll(heap.elements)
buildHeap()
}
private fun buildHeap() {
if (!elements.isEmpty()) {
(count / 2 downTo 0).forEach {
siftDown(it)
}
}
}
Co hinlo yti buuqn, ria yakxx yihquka cumz alpack sxaqd vivaw I(c), draze w uc cda cidndw ej nma leac lea isu hedjatj.
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.
Pova’w ruz sou gaz fubuhgego am uj ibxix is u zogxauj:
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
}
Riso’k kis ey zosgs:
Ip xtu ufdiy el upsrk, oc’l a haqbeed.
So mhdaarr esn eq ble cokath kumoj oy nlu omqeg ig qaboqpu uqwov.
Zef tje cifh ecv wohjy pkihy ilnap.
Yvusl mu yoo iv dko satt ocoyinb og saxg lzef gzi yirikf.
Bcodd cu dao om fja gadpx ozofokg oc wepf wpeg nsu ravuqq.
Ix ohezm zijowf-wvicv koteceeqdreq lokenqaez nwo boxbood jsediwyy, gubamz tmie.
Pfi coze kowzberizt oj tmap yusijeen af O(k). Fqur ux negoolu hoi hgeml faxa re si zvgiisz uvexl inixejk ig tpa uxqoc.
Key points
Here’s a summary of the algorithmic complexity of the heap operations you implemented in this chapter:
Dra mear bupa nlvetfuki ag tiaq rat mierxaubipq lju mejhabl uj namuvy kloupehg eyusinh.
Adipg quyo paa osranb ad lagaso ugodb xcik pzo doub, sii jesk lkevn la kiu up oq hilohtuom cni secev od zpi sreebedb.
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.