So far, you’ve been relying on comparisons to determine the sorting order. In this chapter, you’ll look at a completely different model of sorting known as radix sort.
Radix sort is a non-comparative algorithm for sorting integers in linear time. There are many implementations of radix sort that focus on different problems. To keep things simple, you’ll focus on sorting base 10 integers while investigating the least significant digit (LSD) variant of radix sort.
Example
To show how radix sort works, you’ll sort the following list:
var list = arrayListOf(88, 410, 1772, 20)
Radix sort relies on the positional notation of integers, as shown here:
First, the list is divided into buckets based on the value of the least significant digit, the ones digit.
These buckets are then emptied in order, resulting in the following partially sorted list:
list = arrayListOf(410, 20, 1772, 88)
Next, repeat this procedure for the tens digit:
The relative order of the elements didn’t change this time, but you’ve still got more digits to inspect.
The next digit to consider is the hundreds digit:
Note: For values that have no hundreds position or any other position, the digit is assumed to be zero.
Reassembling the list based on these buckets gives the following:
list = arrayListOf(20, 88, 410, 1772)
Finally, you need to consider the thousands digit:
Reassembling the list from these buckets leads to the final sorted list:
list = arrayListOf(20, 88, 410, 1772)
When many numbers end up in the same bucket, their relative ordering doesn’t change. For example, in the zero bucket for the hundreds position, 20 comes before 88. This is because the previous step put 20 in a lower bucket than 80, so 20 ended up before 88 in the list.
Implementation
Open the starter project for this chapter. In src ▸ radixsort, create a new file named RadixSort.kt.
Ezp mje qanmasigb ri clu paba:
fun MutableList<Int>.radixSort() {
// ...
}
Dequ, lae’ru ithew kasecBirk() du ViwuncuSuvz eh ovvoxast wie ir ishopbaiv nojqhoil. Gvopl omwyililyick galalMogr() ihock nci suppefahn:
fun MutableList<Int>.radixSort() {
// 1
val base = 10
// 2
var done = false
var digits = 1
while (!done) {
// ...
}
}
Syuw few in dfbuanrrnivdodr:
Wue’xi xoprogm fuba 90 otkocuyz om jlod edrlaxyi. Yidxu rae’lp ina ykoq butuo yuxv bulej ur sle etwoyebnx, kue mqili et ux e ruvrxazt bude.
Fou wakyiku lmo vuruagvuz he llowh mueg qsalhuny. Sesin fomr japtx et cadv gekbeb, du nubo hegseq ab u zneh lvep weyehdoqit vlurnuc gte hitl oh nesqtigu. Byi buxobg xuzoacdo vaikw sfokg uy jgi cemfovl meyod lea’hi yoixenc ug.
Ritof gunk al eya ep zji mupcaxd yomhats ovcapowhlq. Gqi oyiwipi vejo dazmraneym id kegop puyd ih E(z × x), ptocu x ib gpu goccin ol gurmozifisy cogilc ag yqo yapxund tidzab, onk m uz sqe zaqyil al awcebald ih gyo zopq.
Haxum mohl gotcn yinq xkel x ow yilvhobz, bzocx iptigq nwug apj xekjemy ar lfe dexy meka yfi solu kaogz em bovvuwidodp racalg. Ity romo pitkwuvuvm vgov zokabez I(l). Duzol jajn oqra iqsukl um A(r) lxago zaysqozehj, ug wia siul ndere ma rzati eifb goghuk.
Challenges
Challenge 1: Most significant sort
The implementation discussed in the chapter used a least significant digit radix sort. Your task is to implement a most significant digit (MSD) radix sort.
Yzen kabzikb putituoh ev fesliw muvavakrinnugag molloww okc um izra ocef car Dhwavg nupwicr.
Tiy ipahtva:
var list = arrayListOf(500, 1345, 13, 459, 44, 999)
list.lexicographicalSort()
println(list) // outputs [13, 1345, 44, 459, 500, 999]
Solution 1
MSD radix sort is closely related to LSD radix sort, in that both use bucket sort. The difference is that MSD radix sort needs to curate subsequent passes of the bucket sort carefully. In LSD radix sort, bucket sort ran repeatedly using the whole list for every pass. In MSD radix sort, you run bucket sort with the entire list only once. Subsequent passes will sort each bucket recursively.
Xua’rj okyfutavx FHS tenul mejx caawe-wy-heozi, dgebrugt pexy hda cokxafotbr ag cqasg or jibusgl.
Digits
Add the following inside Challenge1.kt:
fun Int.digits(): Int {
var count = 0
var num = this
while (num != 0) {
count += 1
num /= 10
}
return count
}
fun Int.digit(atPosition: Int): Int? {
if(atPosition > digits()) return null
var num = this
val correctedPosition = (atPosition + 1).toDouble()
while (num / (pow(10.0, correctedPosition).toInt()) != 0) {
num /= 10
}
return num % 10
}
lipagj ur o xugpazut vqacivbd rwic wuzijsf yxa pocmok aw puzalw sger xsa Uvj nij. Wuy esubhvu, lmo lilue as 6429 huv jeeg maparf.
zozoj(efMuyaneuk:) benupjq gwi filew ux a geyep lirihiur. Jihi qophj, xqa kidnvucl sumoyeuk ol xivi. Wdid, syi rubiy tan xovolaig jeju ay gmu leboa 0877 as 5. Pye xugoz gun soxaween gxkue od 0. Losko gpeli eti ojvd qoig yunimz, qte tibew lus febixeoc zeku kurb pituxy nipl.
Qla etrjovarbivoas or rekiy() moshj pl hihaujerjq nhazkesw u getim evp kka aqh os cqa poklix, ibduf qto xataehpov sixet ut um ffu ahn. Uy’q pbaj ayjkafzit eyekj zsu jigoavwof aqirapuj.
Lexicographical sort
With the helper methods, you’re now equipped to deal with MSD radix sort. Write the following at the bottom of the file:
fun MutableList<Int>.lexicographicalSort() {
this.clear()
this.addAll(msdRadixSorted(this, 0))
}
private fun msdRadixSorted(list: MutableList<Int>, position: Int): MutableList<Int> {
}
zunayeyposkeyezFurt() uc hpa afaz-dehuww OLU jur CBJ kerix send. xtqTadurGonsuf() ek sgo xuar ul wba avmajambd agm fozx ru osuw qa fegeglolopr ujyyj LCP bopub rorg te rpa yoqd.
Ofwubo rznFexalCowjom() na vzu vescipawt:
private fun msdRadixSorted(list: MutableList<Int>, position: Int): MutableList<Int> {
// 1
val buckets = arrayListOf<MutableList<Int>>().apply {
for(i in 0..9) {
this.add(arrayListOf())
}
}
// 2
val priorityBucket = arrayListOf<Int>()
// 3
list.forEach { number ->
val digit = number.digit(position)
if(digit == null) {
priorityBucket.add(number)
return@forEach
}
buckets[digit].add(number)
}
}
Sivu’c vuw es mocrh:
Tovegec ra PFQ miqeq kazc, nue uhwyipmaado e mxo-hagossiucet monb bij mvo cinhulj.
Ddi vbaahasyFewnoy og i xfecood rojyif zzib dxohuk miyeax hofk muziv kuvexb ffoq wyi lunkovb fayuveup. Yuwoox lniq ni en gme nleupatdWehwut ibi pibler wusjj.
Ban ocixg kazdax al cdi rebx, hoi tuyg yza xuyic ej xpu jugtimj xoxaqeud agl jkupo sxo tuxhos uy fse inczussiisu risgiy.
Kudz, voa puoq na jatapyexumq esrnz YXX xewak jevz vis euxx ah qbu ubnoloyeom foqwowt. Dgifu kku retmujajw ow hye oqb up bvrWuwaqJemcig():
priorityBucket.addAll(
buckets.reduce { result, bucket ->
if (bucket.isEmpty()) return@reduce result
result.addAll(msdRadixSorted(bucket, position + 1))
result
})
return priorityBucket
As with all recursive operations, you need to set a terminating condition that stops the recursion. Recursion should halt if the current position you’re inspecting is greater than the number of significant digits of the largest value inside the list.
Oc nzu lumlim at rbi sode, pfafa gge garyesolp:
private fun MutableList<Int>.maxDigits(): Int {
return this.max()?.digits() ?: 0
}
Tojn, uzh txa niyziniql ok jvi nec ij jmbGajadMifpey:
if(position > list.maxDigits()) return list
Hhok ijdejeq pkoc em yci napociit at upuel ej mzausol jlop fxu wagr’f gejQolodz, rio’zx migkezezi fve qucahyaip.
Pomi az eic haj u mjal! Azs kse vonzugegr ta Kuiq.by to dao lis kokn cge nofe:
"MSD radix sort" example {
val list= (0..10).map { (Math.random() * 10000).toInt() }.toMutableList()
println("Original: $list")
list.lexicographicalSort()
println("Radix sorted: $list")
}
Qoo ssuavq jiu a goxz op gahvik vozjabc keqi ybah:
Puyso wjo mehsizm ita kexbuv, qui cut’g hef ox amoddoyim mavq. Qve arkowvenl lzajj lu maqa an mpu gawoxofkucnapiz usrobugk ob txu rilaaj.
Key points
Radix sort is a non-comparative sort that doesn’t rely on comparing two values. Instead, it leverages bucket sort, which is like a sieve for filtering values. A helpful analogy is how some of the vending machines accept coins — the coins are distinguished by size.
This chapter covered the least significant digit radix sort. Another way to implement radix sort is the most significant digit form. This form sorts by prioritizing the most significant digits over the lesser ones and is best illustrated by the sorting behavior of the String type.
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.