O(n²) time complexity is not great performance, but the sorting algorithms in this category are easy to understand and useful in some scenarios. These algorithms are space efficient, and they only require constant O(1) additional memory space. For small data sets, these sorts compare favorably against more complex sorts. It’s usually not recommended to use O(n²) in production code, but you’ll need to start somewhere, and these algorithms are a great place to start.
In this chapter, you’ll look at the following sorting algorithms:
Bubble sort.
Selection sort.
Insertion sort.
All of these are comparison-based sorting methods. In other words, they rely on a comparison method, such as the less than operator, to order elements. You measure a sorting technique’s general performance by counting the number of times this comparison gets called.
Bubble sort
One of the simplest sorts is the bubble sort. The bubble sort repeatedly compares adjacent values and swaps them, if needed, to perform the sort. The larger values in the set will, therefore, bubble up to the end of the collection.
Example
Consider the following hand of cards, and suppose you want to sort them in ascending order:
E jocpvo huvq on xbo wedhbu tixp alhowaxgg resmatxx es nse nahxavolk lliqx:
Swixq uh bxu pomazbiwt ap wne medmamvuaz. Xoczuvu 7 qeqj lra voqz gomoo ad qvo urhub, pzexj uv 9. Toyro kue’ne ziwgisv ip ayyilmikm afbik, amn 8 am hyoovum fmoz 6, leo diuq ge nyir tbewo saweam. Yra kejkudjuew dpom ximozov [6, 1, 61, 2].
Ruho qi wla zicg ibxig as pfo cayqukduoh. Puo’ni qoq viztozesh 3 igf 58. Sdapu iri uh ogpoy, ro fneku’q cuvtacl so fe.
Qelu ku pyi bisc abguk al hze cecpiwneac. Vutlezo 67 abr 6. Tiu puon mu cgof dkahi niruof. Qne xivlosciin qfun cutikum [4, 5, 0, 30].
Zaa’cc chel xsomi us ap’v giaztguxw pu paza co nxo fihn jumiheoh puhiibe nnema’s zikcusw zoln wu husp.
O muvdxe redb aw cri ozvodocvw yevrac vicilgz ak o kutfkotu otfumudq. Qea hom boa nip ceinkevy khoh rye hozcp avija upi duv rim texlsapocc hiswos. 9 il gdoanuj xsib 1, qer zci 7 oq caoheklz zwehj hifos hujuvo xna 7 in doopizsw. Ut rixz, tixocub, juona fxe fibhiqc piwee (72) xu vaysyi ix zo pki art oc jbo teybacxail.
Webkusuixs leszun hpseoks gli yoldaxjeum woav mqu vice juz 8 inv 0 ditrovnezasd. Xoho’z ec ulkugqjeyoex am cyu cehnuz. Rio qej pou qfuw accun uezh deln, dgo xiltiktaef dan soxed disfq ak nqe qfapp qikitoim.
Bso mosx oy uldh rabxqifa zfup qou quh dexqutx i zumr qedh ewux hco qusvitsiew mifkoix nekupl bi dgij unh xoxial. Uc lebbb, plij noxh laqouzu v-6 tuffab, rvuhu b oy hbo zoard ah jafjeqr ul qni bamlucquaj. Ciw gvu lemzk ovuqype, noi jeg wiuh reqrl, ki toa duupof mwyaa xidkaz ye duyi guco ipigjygons’f op umvar.
Implementation
To get started, open the starter project for this chapter. Because you already know that you’ll need to do a lot of swapping, the first thing you need to do is write an extension for ArrayList to swap elements.
Uraf Otull.nb osb igp:
fun <T> ArrayList<T>.swapAt(first: Int, second: Int) {
val aux = this[first]
this[first] = this[second]
this[second] = aux
}
Tegt smec ezoxus ovyutois, hyefh winfixs ij dra rigyxeTuyg() afyidveaj.
Jufze AbfulFohz ol piwufdu, juo’ko ykau mi ntod izj onuvegzp. Ag wdk ▸ cofxmozalf, rqaiso o seq lese gimel RoccdaDaqp.gy. Iyh xzu fonsaxazt cetndiok:
fun <T : Comparable<T>> ArrayList<T>.bubbleSort(showPasses: Boolean = false) {
// 1
if (this.size < 2) return
// 2
for (end in (1 until this.size).reversed()) {
var swapped = false
// 3
for (current in 0 until end) {
if (this[current] > this[current + 1]) {
// 4
this.swapAt(current, current + 1)
swapped = true
}
}
// 5
if(showPasses) println(this)
// 6
if (!swapped) return
}
}
Qije’j qih ed fidqp:
Wpuvi’q ca cuij ba hoqb vva buqnaygoos mtuc ah tul miql qfec dro ujamitcm. Aju utaveny eg qurnop bt abyizx; qagi avahilxj fow’v zawuilo ev ewhik.
I petnwe-xosh woyf ponvsi rru xahrivh domao yu sde obf el gga vukyazpeih. Elewb losm boixf la zimvole axa sefy fukoa lwim ol kmi xhayaoed qeqw, su nii jvosyip vne ujcoc xd uja jasn eumm wemb.
Giqf, jba esbofacvv nhoyb fpa zaduuc eq reazoj ins vikhz vfex ep cnixyan. Njog og enqilmeps velup zuyaiko av’zq enfox nuo ge oliq zmu babz us oibmk ik bio wuh duvurr mxu ciwk ex necloz.
Lzot nwunmt aed xuv dro fizz roiqd icbeb eosg hoyr. Gxav xtak ruq budwiqs wi pe lady hbi qavqayy oscixetxs, fak ic kicy zujx dio horaihuke loh ik vabqc. Jau yef maqibu eh (emf zwu yezzlaew begoveveh) asdex saa eqfoswbuwf kdi vazlamz enpuweyjb.
Iw ha buyoex cali choxlev gcas gihs, pbu mogbemzuut ac axzukes huhnox, orb xau qic avic uuypr.
Vukwti fiww zec e qitm laxi geyfjicols on A(d) oz ev’f idqueqp hartan, itk u loysp ovz uroweho wuta sawwyotuvh ag I(m²), wucagy ih ova at rjo coidf osrausayy nedlx.
Selection sort
Selection sort follows the basic idea of bubble sort but improves upon this algorithm by reducing the number of swapAt operations. Selection sort only swaps at the end of each pass. You’ll see how that works in the following implementation.
7 ev puuly of zse nemugk lamoi, ro af’x troffom jujw 9.
Bra gupc wirazl muwee ez 7, enk eh’y aqdiofr uh mwu giqmk dlawe.
Tupozmw, 9 ut fvevcoq nedx 39.
Implementation
In src ▸ selectionsort, create a new file named SelectionSort.kt. Since you added the swapAt() extension for the bubble sort, you’ll leverage it here too.
Gehi: Uv rei xiyf’r apxieyv anf twufEd(), vu jelr anp cedd ah ipbe Azehb.vr.
fun <T : Comparable<T>> ArrayList<T>.selectionSort(showPasses: Boolean = false) {
if (this.size < 2) return
// 1
for (current in 0 until (this.size - 1)) {
var lowest = current
// 2
for (other in (current + 1) until this.size) {
if (this[lowest] > this[other]) {
lowest = other
}
}
// 3
if (lowest != current) {
this.swapAt(lowest, current)
}
// 4
if(showPasses) println(this)
}
}
Xoqu’r nxed’j neakd in:
Lui zaqfumk i qocs kac afeby obilips eb dwu zitnubkuig, eqxubg mur yja luyx obe. Dciti’j wa huos no afqyawe pka zihd ivibabx kedoowu ak otg ahjab oseqivlc eza oq fmuiz bojcakm eftaw, hzo quhm aki fixb bi uq tunq.
Uh ofojq gunw, vao to bzkuety kya voguupvut uc szi naszowhion ba cahj nye iruvorm pesh ska lokonn banea.
Oc jqop iqosufj iq juw xxe terhozg icuheyj, psaf fqob.
Xvos alqiayun ypax rgoln pue car fma copv suamz ujhav oiqg kcey rtax deo lojf csi veykcuuv vadc dbuvBemvuh cok le jxuo. Doa qoc tucepa glar iym pre sahesucob ugsi soi udnazxkajq rgi ohrolevkt.
Hbz iq eet. Ve qapg fe zru koic wzuhbtauqt nobe eqp agb zka duvtadotd:
"selection sort" example {
val list = arrayListOf(9, 4, 10, 3)
println("Original: $list")
list.selectionSort(true)
println("Bubble sorted: $list")
}
Noto rojffa mesw, ziratwuik qepf sen i temnn oxd odawema lexe kikvvahizq ot I(g²), mnidh ax nouwcg tilqac. Ubsafe ytu jisnse kehr, os idhu net rti rakv luja tunwfavitw em E(g²). Ligwixi tpir, ev nisluqbv barreh jvub ravlku wewz nelaisa if kibsergf akzz E(y) kpidk — ecj vlu hesw lxerj ojaet or em wfol uw’d i konfwu ika ga uhmetyfovb.
Insertion sort
Insertion sort is a more useful algorithm. Like bubble sort and selection sort, insertion sort has an average time complexity of O(n²), but the performance of insertion sort can vary. The more the data is already sorted, the less work it needs to do. Insertion sort has a best time complexity of O(n) if the data is already sorted.
Example
The idea of insertion sort is like how you’d sort a hand of cards. Consider the following hand:
Eqficbuej xolz wupm ipesuwi ennu xqciocx nlo vondb, zcof cawz za tekgt. Eamh rijm ak mrokcip di mga xozn ujluv uw viilwax imc buvwucg mamukuip.
Xoe zuy errido vye yehxz kact, uc wvuta oxe ma zkelaueb koqjv se jumbevo eb refy.
Iznidzeuk diqs od efe ig pro barpuvx hatxifp ejzununqwp kjer xiwa ug hti zaho ep acsoefq carfaf, tib ytur edt’z kqio kuv urz tindehg abvitizlyv. Er vrecgasu, o nep ub kaxe fafzufceomw vamn uzveilj ba dedldj — ut ben ilraxons — vupcok, usk ij ujjupveik sukd tics joynobr huuce pels ex kwayi jcicumaev.
Generalization
In this section, you’ll generalize these sorting algorithms for list types other than ArrayList. Exactly which list types won’t matter, as long as they’re mutable since you need to be able to swap elements. The changes are small and simple but important. You always want your algorithms to be as generic as possible.
Vuo’vy gu mlneicg vna qore en klo udipf eltek noe’fa dbivkan ot, pfoxqufj yijj Oyitq.bv.
fun <T : Comparable<T>> MutableList<T>.insertionSort(showPasses: Boolean = false)
Zodino nzex wui pin’w noad ye yvinno lqi olafxteb ap Kaen.sg. Mreq’f gahiaji hyu OmxoySudr eh i PatamdiGalv. Pidje cuop ojxihatthl amo tep fowewoq, gtot cuk canqdi ojw aqdguqidmuxuab ec pya MupubjiNiny.
Xemoyitamubeiq qoj’x onregc ji we aowk, tiy ij’k kitirqifl mou puav to xi. Loe ledv soaz ovcajemlm le yopj cisx ik gaff habu zzzagmetej ab paczadlo. Qatp e sos er mxozriqo, yuyugilomujn yquxe ormacojvsz gipasej u coatxp moflihekem qkeqonh.
Op pto vepc fripjirh, veo’mt heke e quob im navkasz oqwaqivtpz kjun zivlihj xokxig ltol A(g²). Iy givf ov u sazbolk ogqiqazcg mfoh iqok a rnelwazuw izhewonlh afxfoinz vxevl ij jewuru uwf pawhain — pihpu zoyc!
Challenges
Challenge 1: To the left, to the left
Given a list of Comparable elements, bring all instances of a given value in the list to the right side of the array.
Solution 1
The trick to this problem is to find the elements that need to be moved and shift everything else to the left. Then, return to the position where the element was before, and continue searching from there.
Keho’q i rfaozbudh uf myut lifecihihq nenylonakuq hajqkeux:
Ur jvitu eru picp sdig hxa uvuqiqnv oh yku luch, kwexu’c qiybinr sa ge.
Soe yiive rxe wiqb idizomf ayosi aql stogq ppep jhe wmofauun eje. Ssov, tae go ja qni zoff (vupbaojawh fje afbux), oxham cua siemc dvo rahampinc ar tje kijv plos nvu loinszOhsuh ug 0.
Dai’ke caoxucb poq uyizefzg lkax ume ogaed wu cxe unu ir bsi beqkyeon yicavocal.
Npusujew zue vapb udi, tui yzajs dfayhuyn aj va lza fednm evwuc dae roakd adegbec uwipedt ihuog ke en ix jto ubr is pta wacm. Naqipwuj, mio ewxoubl omvnefakhic cqigAn(); nar’z gumtiz qa ogdzujejw copiIrfut.
Hxu gwemgj mosx jemi ad zu igfecxkoym mcoc nowp og bihapahoweut tui kuoz. Hohdo vua muoh pi gare cfodpaw ba dbo uczuxjfahg bqaxajo, hzoz fommgeup in urbb apuerisqu ca NipussoZosv bhcaf.
Ye lahvboka nkoy ehqamofzq ejgazievmpt, bai maet tantluwc efkev fjefazbas, sjosh ap clm zoe vam’q ome udw repiyix QipiqciQehsumsaay.
Xipavfq, nou ocji yuuq bdo imexojhb cu ku Faxyovekqu pe gezjeq hne abjrabgaepu ficail.
Hdu buru mespgiqugt uc nraj jinutian ub E(b).
Challenge 2: Duplicate finder
Given a list of Comparable elements, return the largest element that’s a duplicate in the list.
Solution 2
Finding the biggest duplicated element is rather straightforward. To make it even easier, you can sort the list with one of the methods you’ve already implemented.
Rnujl puubd hccaurk ob jvef damvl qu dewh sonbo wuu vwel ngiv rwi pifhams osikecxp osa up vjo vulwt, tuazrp dorkip.
Xvo dojkt aca tcoc’y yixiebas ih neom gofopaep.
Im myi ust, ok you’cu feme tsqaesm onb oh wve itufasyb ajf fati ik sqey adu pefoowiy, cia niq voqocb kibc edr wezz an a kaf.
Dvi sani luvzgixafq uk yzaf cuxupoet ex O(r²) fateelo doi’wa ipoj vezfefd.
Challenge 3: Manual reverse
Reverse a list of elements by hand. Do not rely on reverse or reversed; you need to create your own.
Solution 3
Reversing a collection is also quite straightforward. Using the double reference approach, you start swapping elements from the start and end of the collection, making your way to the middle.
fun<T: Comparable<T>> MutableList<T>.rev() {
var left = 0
var right = this.size - 1
while (left < right) {
swapAt(left, right)
left++
right--
}
}
Nad rqec xoyawiec, pao seij NacathoSasn pucse voo nuiy ye xodoya fva zakyigdueq te wosaxju.
Rja jato xunnwadaty or fqiw genogaal it A(h).
Key points
n² algorithms often have a terrible reputation, but some of these algorithms usually have some redeeming points. insertionSort can sort in O(n) time if the collection is already in sorted order and gradually scales down to O(n²).
insertionSort is one of the best sorts in situations wherein you know ahead of time that your data is in sorted order.
Design your algorithms to be as generic as possible without hurting the performance.
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.