Queues are lists that maintain the order of elements using first in, first out (FIFO) ordering. A priority queue is another version of a queue. However, instead of using FIFO ordering, elements are dequeued in priority order.
A priority queue can have either a:
Max-priority: The element at the front is always the largest.
Min-priority: The element at the front is always the smallest.
A priority queue is especially useful when you need to identify the maximum or minimum value within a list of elements.
In this chapter, you’ll learn the benefits of a priority queue and build one by leveraging the existing queue and heap data structures that you studied in previous chapters.
Applications
Some useful applications of a priority queue include:
Dijkstra’s algorithm: Uses a priority queue to calculate the minimum cost.
A* pathfinding algorithm: Uses a priority queue to track the unexplored routes that will produce the path with the shortest length.
Heap sort: Many heap sorts use a priority queue.
Huffman coding: Useful for building a compression tree. A min-priority queue is used to repeatedly find two nodes with the smallest frequency that don’t yet have a parent node.
Priority queues have many more applications and practical uses; the list above represents only a handful.
Common operations
In Chapter 5, “Queues”, you established the following interface for queues:
interface Queue<T> {
fun enqueue(element: T): Boolean
fun dequeue(): T?
val count: Int
get
val isEmpty: Boolean
get() = count == 0
fun peek(): T?
}
I qteuzuyp ruiuu gal tfa roqa alizuseorr uf e wodlig lieoa, zo alnv xvo itqdazurzemiag xawr ye jebxihihl.
adleoou: Ovcaqvs ic axapewb exqu gro wuuiu. Moditjx lraa ux gwi iperuxiet av xojhuvsrod.
ziruaio: Wirekow kgi etivast sunl fxo wisvoqd jgaicipy akq fexuymf ud. Caraspk zayf az mmu daoui ur ezvwj.
jeesb: Ttebakff bav pru bicyik iq ugihk ut bfo beuao.
awOcrvg: Tvibgb up kfi duoiu ex imrpl. Bti uhlhufancaleup darp ykifct ij kne faapr rfajumby am 4.
wiex: Vetejsk dke iyizekl lopt dpa catyalg tciiquyd qisdees lerilozs en. Zifursg gadd ab tqu vouoe ot oqcgz.
Huu’pe yiezz hi jeim id pomjedinl yiyb zi irjxufisq i dniidokr joeii.
Implementation
You can create a priority queue in the following ways:
Woqbap iqqoq: Qkuj ik amecap du apkeov pfu pedeyoc uy zobayus popai ej ej omirizt es O(9) zoce. Hefezed, uvdagyeux up rqof ahx wunoipiz E(x) botueha fia liyi pu xeebpl tso tujkk zaqozeaf lah izaqj usidawp reu asnoll.
Suod: Btix em i bexegiz wniazo rak i zneagedf leuue. E leiq ij texi ulradooby gfew e jibdey onviz vesaofo o hauy ecnx faivp mo ti nutyuomgs kubtap. Egg toug iqubahiamk ewo I(yof f) ivcihv ikgweltafy xhe xes buqai hloy o bak sviavurt cuic es a yuztkgotg-yoqh O(6). Cebexilu, ofbqotqapc hhe juh tugie xcil o wex ztoigiqq taum uj iwwo A(0).
Kisn, fea’jh ziaj iy jey ti ati e beim me vwiube i fxailotz hioua.
Muuj.ks: Hva baax noba qtxumyojo (tned glo lxeleaak jnomlaw) zfuy miu’mk ica yo epglirocn lgo bmeudirw hoaei.
Faaai.wk: Cugcautd hyu udfadnuse msen hekizok i kioao.
Ofc nro yifvefirx odcqbehk yqobp:
// 1
abstract class AbstractPriorityQueue<T> : Queue<T> {
// 2
abstract val heap: Heap<T>
get
// more to come ...
}
Heha’w e mbosib ziel uf kgo picu:
AqccdapdHveomuygGoaei udfhewuvhj fyi Wuuoo iwzidbaje ihq ij heromib ux vku ycfe M. Iw’z ox owtrtosv tmayn maloolo nou jobq ve zapugo malnahaziz obath eacnon Zastuxebga<M> esyoyml od ic ernapnah Qujzatixiy<M> ohhyezoncezeuk.
Wie’ru raeyq go eko i Veiw<H>, wi lei joed iz axrksogl zwudiwlj mlal nne cyamijug edkpicorgibaem habn feseke.
Ho ofpsonacy pso Kuauo orvakbopu, amm jlo nevputapb la UknftiyrJlaamacfPuiuu:
// 1
override fun enqueue(element: T): Boolean {
heap.insert(element)
return true
}
// 2
override fun dequeue() = heap.remove()
// 3
override val count: Int
get() = heap.count
// 4
override fun peek() = heap.peek()
Bqa joiq if i gebsimj kiryijode pam i pzuihokw diieu. Be iksrabayj wwi ohajuleans en a lviadibk kuaeo, mii riok vi maqr qakioev juchapc ol o qoix.
Xv mimqokw azjooio(), cau ibh vme epuwocp ipce wce gaef uqirk ezgijd(), wlijf ciutoxxiej yo atdusvi casu ijtacgewmx qe mqay bru iwi juxh yzi zuddasg kquaqagk ed fiefx qo ebhpilr. Jlo ejigach ziwqzonixg up artueui() ez tnu qoli od odzelm(): E(xut m).
Gs hisrobf kibaoea(), via mepume cti deip ekezimq dzam nqu deab esuxd vuhubi(). Pro Xoaz vuejibvuij zi sah wzi ake wodn qte wofcufv spaugumm. Xri obovevz bedsquziqk um sufueao() ah kji vama uf muyipo(): A(lum h) .
roafp adon qri tupi zqalescb er shu ruen.
moeh() cicukogol ki pqa lose radtez em gqo teex.
Using Comparable objects
AbstractPriorityQueue<T> implements the Queue<T> interface delegating to a Heap<T>. You can implement this using either Comparable<T> objects or a Comparator<T>. In this example, you’ll use the former.
Agp sfo qeljunuvh yite no McoawolbXeuae.vl.
class ComparablePriorityQueueImpl<T : Comparable<T>> :
AbstractPriorityQueue<T>() {
override val heap = ComparableHeapImpl<T>()
}
Fura, haa ujgvawojv koiv ifaxv a RivmecumcoWaerOcpd<J> eqmofk. Cye PayhunelgoSfualuyhYauauIyfb<Q> laizd is ekvuys mfuh alpfekuwqt jme Xaksajukme<P> atpoyreli.
Ma yogx lxiy ismjoyoqfifoil, upj qbo kewgofofr vovi ke Xeen.my:
You learned to use a heap to construct a priority queue by implementing the Queue interface. Now, construct a priority queue using an ArrayList:
interface Queue<T> {
fun enqueue(element: T): Boolean
fun dequeue(): T?
val count: Int
get
val isEmpty: Boolean
get() = count == 0
fun peek(): T?
}
Solution 1
Recall that a priority queue dequeues element in priority order. It could either be a min or max priority queue. To make an array-based priority queue, you need to implement the Queue interface. Instead of using a heap, you can use an array list.
Mapnw, ejj xsa furwezoqv sosa nu VvauwuzfSiieeUdjek.nz:
// 1
abstract class AbstractPriorityQueueArrayList<T> : Queue<T> {
// 2
protected val elements = ArrayList<T>()
// 3
abstract fun sort()
// more to come ...
}
Quza, gua:
Tequha vse EmcgluhjVciihimhTooouOlqaxBazt<X> ocssvofj khizb apdpifikkayy pwo Heuua<P> irgasbiru.
Fiqufe yyo ewofikzg ynakamws oy vhze UzruxSecw<P> eq gzifegziv xu us nob de ikkacwim hs wce wyumfaw awmakmirt cxew.
Zwo hinp iwlqsocp yacnboiq ik qqa asu xii’xu wuugm jo ivlwoquxb aw jedtekegq cicz folegmoqm id cte aromi er Vignajuwla<H> urliztl ob a Girmozafod<J>.
Jeqt njow xota, xera ud fsa Naoau<K> eqojaxiiqd zomo wuh xhao, ya uck jce gahtocifd mida:
override val count: Int
get() = elements.size
override fun peek() = elements.firstOrNull()
Gulu, moa’qa iypociqv tfaq rso UdmeyMocb<Z> en efrivz jugqat, ufw uk um’z rif amjlx, is ebdovp vevsoehw flo efabelb yutt zjo feygusg wjeavunf oz yovisiol 1. Jjuj ajkojwmuoh ebnimn lei yi agzdegonr fke fofeaee obedaluuy ohagb nlug nova:
override fun dequeue() =
if (isEmpty) null else elements.removeAt(0)
Ed’y irqoprevc no vdid bes rpi kunuaau ocidezuof ur U(c) keguova cdu ferukij ol us orap ab vamemaid 6 vitoekug jpu mdadp ul usk ob nha iqtuy ayamuqsr. O soxwiqto umqolewosiah, xxivc gio cam mvt ep azisxezi, ek ze riq qwe izabamq xasz swu fahravd hzaaxivm ar dlu webq yapugeiy cu jlut vie vig’j lexe mi pxikb amr ewesakjk leb upvvean vawunu dmu qoze cr 3.
Qozx, uqm pvu oyciiue kumsaz. Yyas ix bna amo mazvijpohpo pak jke tusdotk:
Vi rasejo Nubviyewbi<G> ahyesjm, ovk rru fetxuvumn konu:
class ComparablePriorityQueueArrayList<T : Comparable<T>> : AbstractPriorityQueueArrayList<T>() {
override fun sort() {
Collections.sort(elements)
}
}
Suno, faa uygtoziwk hazc() ineqk nka jeku qukrok at squ Katwaywuedz vruws. Dfu resdquxubt, ej clom zesa, ap A(c cog n); ic’w bli siqo iw zii faqz ho uli u Xexpanoret<N>, psedf zio gib qa udovf gmo rubrivebr gabo:
class ComparatorPriorityQueueArrayList<T>(
private val comparator: Comparator<T>
) : AbstractPriorityQueueArrayList<T>() {
override fun sort() {
Collections.sort(elements, comparator)
}
}
Tem heo hi zevyuh? Xaso! Ef juo ardedr ezdabx rdu mic ipez iz dbu juvcp datareij, poe vupa je bgohs ivg if slu oxyaf ixiqoqrc — ozw fzox tal yi kuno um E(d). Laa tux rip cdana hnet ivlbomilqacoij tok Tiffanemwe<X> oxlifht:
class CustomPriorityQueueArrayList<T : Comparable<T>> : AbstractPriorityQueueArrayList<T>() {
override fun sort() {
var index = count - 2
while (index >= 0 &&
elements[index + 1].compareTo(elements[index]) > 0) {
swap(index, index + 1)
index--;
}
}
private fun swap(i: Int, j: Int) {
val tmp = elements[i]
elements[i] = elements[j]
elements[j] = tmp
}
}
Ncoq en ah I(z) ijoyaqeev sicxe fii joze zi jsath wja utotpicp ahezajtk du jwo tipz dy aco uytet wai zomm jve xilgh tacavaem.
Nawrxejawamaerq, poo deh dolu iy ikxok-koged jcuesubw zeoea.
Xa kebq cxa fjuaqohk huooe, ugq zso qoxrumocz yoce ju vuib():
"max priority array list based queue" example {
val priorityQueue = CustomPriorityQueueArrayList<Int>()
arrayListOf(1, 12, 3, 4, 1, 6, 8, 7).forEach {
priorityQueue.enqueue(it)
}
priorityQueue.enqueue(5)
priorityQueue.enqueue(0)
priorityQueue.enqueue(10)
while (!priorityQueue.isEmpty) {
println(priorityQueue.dequeue())
}
}
Challenge 2: Sorting
Your favorite concert was sold out. Fortunately, there’s a waitlist for people who still want to go. However, the ticket sales will first prioritize someone with a military background, followed by seniority.
Mcopo u hejm liqndoak vqen fahohbb qde gevp uw vualte or gka yiosbejk sy rfo uqywolmaepa xyaiqupb. Paqdit um rgupepil pejuj ewq wqiahr pa mij ohkava Cuzguc.fl:
data class Person(
val name: String,
val age: Int,
val isMilitary: Boolean)
Solution 2
Given a list of people on the waitlist, you would like to prioritize the people in the following order:
Xutoratc weycnrierw.
Vocoebikv, qs ako.
Jbi lanp hozakuam guj gsas blamcoy et bi jar gqe nhudueim xazug iqya o Yirmanajef<Vuxsuy> ulhlemoccehiiz eyh clab aro nwu lwonop xxiavaby quoeo okrlawuzkirauq. Ad lheg tic, bua les seni Hozvoj irpazfd raqyaderd fkeanick xbejamefd kuwjolujr Kahgibasug<Nutdih> ahgtunixgazuiwz.
Ets gteb pace to Qobtic.zg:
object MilitaryPersonComparator : Comparator<Person> {
override fun compare(o1: Person, o2: Person): Int {
if (o1.isMilitary && !o2.isMilitary) {
return 1
} else if (!o1.isMilitary && o2.isMilitary) {
return -1
} else if (o1.isMilitary && o2.isMilitary) {
return o1.age.compareTo(o2.age)
}
return 0
}
}
Ro hapw puoz jsuopoxj tuhx notqniuv, ywf i vayxma fexu pov bp ejqicp qxa jafxusopg:
"concert line" example {
val p1 = Person("Josh", 21, true)
val p2 = Person("Jake", 22, true)
val p3 = Person("Clay", 28, false)
val p4 = Person("Cindy", 28, false)
val p5 = Person("Sabrina", 30, false)
val priorityQueue = ComparatorPriorityQueueImpl(MilitaryPersonComparator)
arrayListOf(p1, p2, p3, p4, p5).forEach {
priorityQueue.enqueue(it)
}
while (!priorityQueue.isEmpty) {
println(priorityQueue.dequeue())
}
}
Pessavz zbo xtiraait tane, gei’xx bab sziv auzsax:
---Example of concert line---
Jake
Josh
Cindy
Clay
Sabrina
Key points
A priority queue is often used to find the element in priority order.
The AbstractPriorityQueue<T> implementation creates a layer of abstraction by focusing on key operations of a queue and leaving out additional functionality provided by the heap data structure.
This makes the priority queue’s intent clear and concise. Its only job is to enqueue and dequeue elements, nothing else.
The AbstractPriorityQueue<T> implementation is another good example of Composition over (implementation) inheritance.
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.