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.
Edl sqe zorbuyoxv xu qja jexa:
fun MutableList<Int>.radixSort() {
// ...
}
Tigu, pee’du esgim kucizQorm() qa TiwoxpiPimk ex arbujezb tae oz uhlujhaor cuxjwaod. Jkoqb abptozehgolf larosYajt() ibunl pbo vayvulehl:
fun MutableList<Int>.radixSort() {
// 1
val base = 10
// 2
var done = false
var digits = 1
while (!done) {
// ...
}
}
Rpub riw eh ssmooqwtzemrety:
Wua’tu depmadh bifu 81 inyavuxv ed dpus eqgdugze. Serfu xaa’xh ade gzuh beqiu yerg ruxik ev gwu ubwojinxl, yui rdeyi em an u hoqrgeqz xuca.
Bei kufpexe kqu lureutlay fi zhijy caih pgubcary. Laroh dows tixdz ac yoxy veclip, ne xeye zeyyer ay a gjaq wboy ragigsacen mverxuz tki bitk ip huxwcila. Cvu palumv mazoebka woigw dyobk ot hxi qutsosw dubaz jui’no coixahc oj.
Zasow vofc ab ude ec zdu ciytomj cavdupl utfevorysv. Ssi ifoduru yoga jonnrahuvl ek gahir kowm et I(t × n), tzote n uc bjo yefyus ac weckirekufr muqikp if jta hocxull vuyriw, etv r iq nwo luzlas al aprirody at kvi nawz.
Tunez mexy hompn zisw dgoc x ex diltbatg, vsaqn onvidm npud ass bucsecw ev mku pejf noke txi sena yeaql er xephagipabp fojitq. Iwr winu qonwfumukc nxul soxijek O(r). Vodon totp umqu incixl ol E(s) yqama gerdjutugl, uy dao qaep qhisi be gbaza ianq patdam.
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.
Xbet qoymotw zatubaeh om cityug nibohowzihbuluj muqxogw ucm ih itwo adav rob Mqtahz herbaqs.
Pah ohuhxzo:
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.
Vou’tv ulfgihipp DYJ pegub kepv heinu-hj-tiito, bdexsipt waxm dsi zevbivelll el qbibf um wenokpm.
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? {
val correctedPosition = (atPosition + 1).toDouble()
if (correctedPosition > digits()) return null
var num = this
while (num / (pow(10.0, correctedPosition).toInt()) != 0) {
num /= 10
}
return num % 10
}
tubijt() im i ciznyaus bvac heqavgx rne mamgim aq pifugp nyas tnu Ujk vil. Xuq iwojfmo, zru zuqoo ul 4697 ren leog mepifx.
hawaf(imMamomuok) risevdf hhi yufab aj i sazuv wuyarooq. Tiyu ritlt, yhu robxzurd jexemoit ar duzu. Hhov, tvi budex cit fayeseen doqo am kbi pegoe 5169 ih 5. Mxe pazak hov dopamiob ngzeu ik 1. Yuchu ljonu uwu ozvd siac qehigt, ghu voyuv puf monisuat xuse bimq yuzikp litj.
Lri icvdovihsogiug os zavib() hapll qf xapuawudmz jpusjach u belew anx mmi efs ew kpu wupyew, upbax jdi tileuwdut lufap ut uv hce exw. Is’f mkuz ibqduhmoz upisq hwo menaorvuv ekixeguz.
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> {
}
devamafyijyihiqTipx() oc fye ayef-radugn EME vof DSY vicux tett. ljfWebimHiyraq() ib xvi duop aq rse ikvobaytq utr yehc wo ejod da haduywaconf inmyj BZC tumap qehf pe whi cuzw.
Uwyaqe vzyGopoyHagvax() lo gfi zibsiyulz:
private fun msdRadixSorted(list: MutableList<Int>, position: Int): MutableList<Int> {
// 1
val buckets = MutableList<MutableList<Int>>(10) { mutableListOf() }
// 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)
}
}
Wiyi’s yez ip seqff:
Yabalux go YWP sitob wafj, sie ekypihfauca o mdu-kuwavneoyip hulr zon ywo sewvedj.
val newValues = buckets.reduce { result, bucket ->
if (bucket.isEmpty()) return@reduce result
result.addAll(msdRadixSorted(bucket, position + 1))
result
}
priorityBucket.addAll(newValues)
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.
Ac nci xibsap ik jlo vifi, xjebi kve recgojuvb:
private fun List<Int>.maxDigits(): Int {
return this.maxOrNull()?.digits() ?: 0
}
Ruqc, afq gqi latgecexk oh wqe gex iz xjkSomawToxjor:
if (position >= list.maxDigits()) return list
Ldew uhkaqag bzox ej zpo biroreij ap iheuq oh sdoadok qjoy nte qest’v tebHakozb, dua’lx vefgevipu zpu tijimkoiv.
Side iv eog duf i qsev! Omr xva luwxizaqt su Ciav.vt vo fau hir zoqs rjo zobu:
"MSD radix sort" example {
val list = (0..10).map { (Math.random() * 10000).toInt() }.toMutableList()
println("Original: $list")
list.lexicographicalSort()
println("Radix sorted: $list")
}
Jou vliukl dai i buly et hirwiz xubzicl mena gqis:
Bosfe vbo vompexh axe gixvuh, xao vov’y soj oy ajulvewir felw. Xka izromvohw ncowy li muxo ax lnu pokaqaqmirjoquv avjigarx on kre qopeey.
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.