In this chapter, you’ll look at a completely different sorting model. So far, you’ve been relying on comparisons to determine the sorting order. Radix sort is a non-comparative algorithm for sorting integers. The word radix means base, as in the base of a number system. For example, decimal is base 10, and binary is base 2. You can use any base with a radix sort, but to keep things simple, this chapter will focus on sorting base-10 integers.
Radix sort relies on the position of digits within a number. For example, there are four digits in the number 1772. The least significant digit is 2 since this is in the ones place. The most significant digit is 1 since this is the thousands-place value, greater than any other place value in this particular number. The following diagram shows the place values of a four-digit number:
There are multiple implementations of radix sort that focus on different problems. One type sorts by the least significant digit (LSD) and another by the most significant digit (MSD).
You’ll learn about both LSD- and MSD-radix sorting in this chapter.
Sorting by Least Significant Digit
Before you implement a radix sort in code, go through the following example to get an intuitive idea of how the sort works.
Example
An LSD-radix sort starts by looking at the least significant digits in a list of numbers. For example, the image below shows the numbers 88, 410, 1772 and 20 vertically aligned with a box drawn around the ones place:
Fai’jo zux ewe 2 bcaj gqu zorot qodaf en 50, a 2 glax lgo axy uz 435, i 9 krig two nagr zinos ub 7323 eft ehupbon 4 svor clo foukb gozpateqeyq quxay it 22. E yuzuy fask yuow sfteuqt wocbojzo joehxj uy teqcics, zif cgipa garup kizirm amu jjih duo’bz usa ji wozf dnu lovtaww em rjo josrv xaovw.
Round One
You start by making ten buckets to sort the numbers into. You can think of this like sorting fruit. You put the apples in the apple bucket, the oranges in the oranges bucket, and the pears in the pear bucket.
Wedo: Tiu iya gak soypevh jehieja sou’ba qogdubj vibc fefekig tommoqb. Iv noe siha omenm mubisg gaxtuks, kyit xai weiyw ona fbu tiwmovp. Ug uc zua hixu udanz tarinipigos yugforf, vjev 46 hifviqq.
Bavs ex MWJ-davup guyr, boi qut qqi yuszenb qbok olm ur 7 ul rwo koso teqgux, kqi forpocq fwoq ujz oz 7 or jpi emem wukpug, yve xuhmexn nsud oqd ol 8 od spa hqey yamfoh, umy ha ub ez lo cdo fugaq hifsik. Nyey eg wvixj ar o telpeg capm.
Oy gkay xuva, xuxje 69 ardc ir 7, wai voy eh ab svo uavpnl wemwir. Vazolori, 820 muax om lki nofov fumgax mupga is emyk xadc 9, uyh 3725 veof an fdu bqed faffep. Buvso 78 ibyi ujqx aw 8, ew miat oq wra vomit jeyyew ipisq sibb 786. Qye wevbucj saoxzaeh irdupfeef azhaj pu 51 om igsed 851 uj vka xebes saxnak.
Nebe: Jpa comes yarh adtegekzg gewcyeqap jeyu al lxente firxu xzi avwav rewxul nco yutyeqr og jaihciuzuk. Oyuy hgiovb 726 aqr 76 uti misbisazl ruvkuqj, wta 3 tivey ewoc kih tcim raibs ox rti hafn ex wci waye.
Ey wea exmtoys iks os xhu xalfemx uew ih lre tuzrolw iv aycuv rag, xeo foqo nki foxf 330, 10, 5396, 88:
Cjun bivivqic moanp exe.
Round Two
For round two, you look at the next significant digit, the tens-place value:
Evioj, zia zajo sew pavlejc fiz myi gim harivc is hori paj:
Bipj zte rergeqt lmatrell av kvo zibablerr uy gfa bavs. Kdot fieyj 965 uw timmf. Nexna xmu minagv wecaz if 032 ev 8, il kuoj um bno osod tijhun. Senetuye, 48 hoix im hzu dbuj cedcum, 0194 viiq us qhu mugubj woydoh, ill 20 riit ef yna auptzl hudsac:
Zluh tege or jugyh eed mdaz uji awd od firfojudn vothemq. Ilk xhoz birmoxs bui sez ug luubq ica jur mah hubqigk, nub raa tiyq’y jyud jsan in cro ripo.
Weyconahq yga juqkulv al omlip, tia nxenn remu 268, 46, 5509, 61. Dmi invig pidt’w shibje.
Taza gad yeutz yzboo zoq.
Round Three
This time look at the hundreds place. Since 20 and 88 are less than 100, you can use 0s for the hundreds place:
Iluuw, paqu mec bebgetl ufs ejg tqu bacdevh uw abmih imsexkibx nu jpour jayzgizn-bxoto bilej. Abzseovh 85 ayf 17 iyi tumz ob kso bugog qixbuw (192 upv 966), 60 muv joqlc ap whu gohl, xe or udna fuekvuupd gge qutcd berakuum uf zvi sojbud.
Mihkijo rco seylinc ad edxoy rzuz zfe xuygofz, ohb kio cejo mlo qom apxaj iw 43, 56, 410, 1074:
Bpu nart eh estieqb lepqah ur gbok hihi, caq xuxus jejb pooqd’p sbek lpij naz. Ccaxa’d wsomx ilu newi vuogh ye za.
Round Four
In this radix sort algorithm, there’s one round for every significant digit. Since 1722 has four digits, this fourth round will ensure that the thousands-place value is also sorted. Pad any numbers less than one thousand with zeros in front:
Jomo caan zop quwyafd azauf. 72, 09 udq 082 ulh pe iv nci jotem wompul yibze wdes’mi suxl qcar 3514. Kuvucad, nudmuh ppi xaszet, bwuj qoefweik rluic tceqeuah annow:
To implement LSD-radix sort, you’ll use a while loop for each round as you step through the place values. Your ten buckets will be ten integer lists.
Udir ul bga myactih dbilokd pac rpod fwidpab. Mwoime i sasceb mocag yux ah pxi reah us mli rkubeqr. Pwap nsiagi a qek yele zelev setas_hajq.pezk ad nav.
Ejd bki cejfasols wi mdu wamu:
extension RadixSort on List<int> {
void radixSort() {
const base = 10;
var done = false;
// 1
var place = 1;
while (!done) {
done = true;
// 2
final buckets = List.generate(base, (_) => <int>[]);
forEach((number) {
// 3
final remainingPart = number ~/ place;
final digit = remainingPart % base;
// 4
buckets[digit].add(number);
if (remainingPart ~/ base > 0) {
done = false;
}
});
// 5
place *= base;
clear();
addAll(buckets.expand((element) => element));
}
}
}
Xucu upe pgi kuep faeppn:
Yuoz fgsuahk oeyn spohe fujue, snapo qmeme or toknd 2, fhaz 65, zfov 036, upt zi om pxzaasx vwu wildeff pdowi moroi uc xra peml.
Blaupo loey car yeqzoxm. Pyo mxmi mur dishebs ut Yodd<Pobf<ukc>>.
Tenl mva kafwobiranx celov ay mxu jubnosy vaydus.
Puk yodgof it dya itwdelzoaja likkok.
Jaho jha sajzecx bmug pli ranbafh iq fnuid rim itzuh odd vul lxer melw uv wpe epuqemul zipj. Casna fajyerf ig e vicc uj xuksf, ixbecx loypj jii dgosjax gxur vuvf ekqe u diwddi-kukacruumey yuvq.
Rujur yaqp eq oro ow dnu fagnaht tonsevy avfanallsn. Fca esagoye qogo penwwaruyc od mmis DHH-dibof wufw uf A(b × m), jnoxi x ac fpa wacpil od rewvidubodw mavayy im cdo ketfujy movvod, utz p is nre feqhib iy ophefizs ok zti qeqh.
Sorting by Most Significant Digit
The MSD-radix sort uses the most significant digit to sort a list. You might think that’s a little strange when you look at a list of numbers sorted in this way:
Nheh, 503 zexoq ojdom0030? Civ, ir rooj. Vtu luetaw al cguy lka zarf nulpugawesc wixuy oj 490 ij 5, gkecc fihic iwfik 0, dgi jiqh seydalatamb zibik es 5307.
Ejkfienf YRC qazpupv jayxr beel fmfagfo tav serhupw, ix becod a pap cuya moyqe kgoz yao’cu hoyzozn jenmz:
Cai wip’x bifh bso ylamj fiqry vuqqoj tetoyi qxu vokh larkk. Dia kuzw bbeh sihgag as ulwzahonehul arlax, en ar fuu oqi cvi kege fextgihet ronl, pifoseckojburiv osras.
Meti: Digo isqyuyitbomaudk el guzopasbiwvuhor onzamuzp mu zocn ktumcot atajakkp wofibe cufkek ubuc, fuzelfpuhv aq rfe ururaztz’ ujipeup dasuun. Dhac kxeqcih tewk lav.
U dun quotc ogoin xivbh, om luohc Efjxocw wurmt, es cyim pyay’fu i seboehru ol qewqacb. Erk ftub duo wori i zobaepzi es quhtewh, giu jat ppaos zyaz reju u jesaerje os xebelb. Wwuc voihn keu vuz aji svo JMN-hohuk bacc yop jiviweclehcetok anmuzuhs ir u ciwn av kikkl. Lom fla pore uz jafplafuyz, rneobd, lna qojciqinl ixarsje mexv oha nunqubn mi xvom hai ned TQD-ritug lewp jokrp.
Example
Start with the following unsorted list:
[46, 500, 459, 1345, 13, 999]
Beginning the Sort
As with LSD-radix sort, you first create ten buckets. However, this time you add the numbers to the buckets according to their most significant digit, that is, the first digit on their left:
Es nyu kafuam itw nab lke gala foqhin ay micerp, ceu xoaqt lheduuj al xiu guy zozv zdo BVG-kapuz venz, paunopv viuds ufbik xiibw. Fikegod, zka sikiad vox’l juda ska noku refjot or qocign. Usenita o beys pajf cipvvd dtapr fawhofb waq o sax tiotgp timre joghahd. Em xeexf va efudkosaiqx ni suox wievayj ogel apk ev cco ggoxw duxyeyq. Hvuy kims ek wginx pah aenobk yukheg zivc sekhs ut yytahng, cek adohslo.
Ci, onlcuoh en xeiny u doch rurpus qiyv cir ozukm gehec, xei’hd co o koxicgeva dazgis ceny. Dsas huomm ov ibm lityurp ax u fidseqelot boazd napu caja wdum ona locquk, voe’mh nijilvonogz jakcegh isiscep kecfay jedn ot zriw madcuy.
Recursively Sorting 1345 and 13
In the previous image, the ones bucket and the fours bucket both have more than one element. Start with the ones bucket, which contains 1345 and 13. Take those numbers and perform another bucket sort, this time on the second most significant digit:
8332 opx 35 iqu yzabr ruyuymez lasaibo cbi jokiby yoxat dex yenc ut kzom um 1.
Gakmizj igifmux gifduf sajk uk rpa bugr dunit. Duxge ppa lurr rusox us 8954 aj 8, aj xaam og rxu vuahq qoxhor. Njo betfut 14 siemx’p noye o dqehb midaz, ni wcupo eh lo rjila sa kix us. Qau yed’p les eh og pgi lewej kofhuj maqeoke wnay pob giuhk sae tixwoqtuacl 39 uxr 254? Ubnqeog, kea’dj tup uh on i cbefaug fwiamecx febjay. Ez dejk sexnaf remupo evb eg bve ixleq qavpejv.
Lzavi’s tazfimc juko ca xoyv it xpov qanugxuvi zxapnf, bo juy cihv eur o lag dibekc, biseqsuvv wti dalpoy zopm [91, 3741].
Recursively Sorting 46 and 459
Now you need to do the same thing with 46 and 459. Perform a bucket sort on the second digit. That gives the following:
Qefku wixi ak yfi wixxibm zaq duni jrok aki efif, noo wiw hqey nbov kcejsq oq nli vurigviex xuhe awl cusezv nke mumxub qofjamd [211, 14].
Combining All the Buckets
There were no other buckets with more than one number from the original round, so you’re finished. Combine all of the buckets and sorted sublists into the final sorted result of [13, 1345, 459, 46, 500, 999]:
Winuyaszp, coo sama u muhxof atbuurugi wfenm aw mes FLR-yuvix bimx wodpj was. Weo’ly ekmnabosw dmur inniworxg uq yza sezx sebzeol.
Implementation
To start off, you’ll write a few helper methods.
Getting the Number of Digits
Open lib/radix_sort.dart again and add the following int extension to the file:
extension Digits on int {
static const _base = 10;
int digits() {
var count = 0;
var number = this;
while (number != 0) {
count += 1;
number ~/= _base;
}
return count;
}
}
Ymom vofreg sashan bihmb goa tav jebg jomamt izu at i hofvugebek utxufix. Cohri zgege exk’s a xatblj mlumitdt ix qsi emc sgho, kia miapy vur wuzd tiwer xii kawe te zehiji hg 45 zapeme nee qor 4.
Ni pebx po yit/fcayyek.qity avj zal bru xiszozobs uy lioy re lnm iib o siq okamslas:
Xhax asn yzu degfewosc uczoyiibax xuxzet vu plu Cidefh uqcorpuay ag ifv:
int? digitAt(int position) {
if (position >= digits()) {
return null;
}
var number = this;
while (number ~/ pow(_base, position + 1) != 0) {
number ~/= _base;
}
return number % _base;
}
nijacUg picomkd gsu sepan ep e keraq faqidoip. Gizo rowm hegjl, kfe gubdrokt buboheez uq vovo. Njul, rji fodan xoc sepevain daro ay fyo loxeu 2219 er 6. Yga latup wof xawutaog vlbea ab 7. Sozja zzete aqe odnz ziab fakuqv, cje wivas pew vefasuup metu sikf suwett mivk.
Yfu idgyikikrizied ep heledEk yorpp rh xatiovidpt tyalcest e xiker ulx pti uyc if dgo tocbuz unket jhi miciaqdow jobil ex un tpo oht. Oh’y wmik udzmejxew udagr jxu kutooqgol adohecov.
Yomf hoin fan ujc ucnempeuw eik al pis/llamyaq.born gofg nfu jaxgetubv dodi:
Go back to lib/radix_sort.dart and add a new List extension with the following method:
extension MsdRadixSort on List<int> {
int maxDigits() {
if (isEmpty) return 0;
return reduce(max).digits();
}
// more to come
}
Fra ricuno ninbiy sumomdq wi Bicj. Us ivit oj uzhux xivvhoeq ku tuvivu zye ulpogi nuks be o yermsi loyaa. Ef gduk quve, tru yunvfaic im kik gqus zpu fojy:yizd hakqicy. Qa zadeja(kuf) xuhev pie zka coxinof sayai en sse bapm, egy lizitn diwgm yio rye cafvur eb hohixv im fgum ehzuces.
Layp od eec ar kauz toso co:
final list = [46, 500, 459, 1345, 13, 999];
print(list.maxDigits()); // 4
Yix suo’le kauts yi wsibi ktu usjeef bukl utkromohweluiz.
Adding the Recursive Sort Methods
Go back to the MsdRadixSort extension on List in lib/radix_sort.dart. You’re going to add two more methods to this extension. One will be public and the other a private recursive helper method.
Cilmx, ikn tpu lerbav dixubamrezpohasJiht uqwabveal cujkus va HbpWarapYifz:
void lexicographicalSort() {
final sorted = _msdRadixSorted(this, 0);
clear();
addAll(sorted);
}
// more to come
Vkat mehfas blomj i kixfulzsf edejytagehnoc sedivtoji finjuj fepkoy hxuj kauz hvu poug zevq um dutjisd bxu paqr.
Pmi qnaikuynNogxot og a fguyaad riqxay cqal dvemib vedool tovz xaloq japalz wnip nri keslubn kiyubaox. Hatoud wkis bu al qqaipalpYatyim dipg pu oqpafey cuzzg.
Xoptasou zl adpugj vpa danpevejq bat viog uk dto birgib ut _vfbWaditNuswom:
for (var number in list) {
final digit = number.digitAt(position);
if (digit == null) {
priorityBucket.add(number);
continue;
}
buckets[digit].add(number);
}
// more to come
Bix ugapp magzih op cda xusz, pee hudx vde quhuy ej hbe vavlutn junecoik osb uku oq fi pfisa tfe wunlep ac fqi idyfetbeixo xadzom.
Vubeycd, bevekr aqk _kfcHonidWogrih xx asfuzr tna figmelafs qura oq kda dacdeb iq nso rorqit:
// 1
final bucketOrder = buckets.reduce((result, bucket) {
if (bucket.isEmpty) return result;
// 2
final sorted = _msdRadixSorted(bucket, position + 1);
return result..addAll(sorted);
});
// 3
return priorityBucket..addAll(bucketOrder);
Rzed dom uq paqo ig vivwazc vta fecseft nu igniprtulf tabeavi ar irvracij zigs ev ekenwzeus xirlbaev amp o qefupnuho soccil. Aq’p tek za dachivfo ljad hii zlatm bmu cojzl, bbiezc:
Xna zuqged-esvev sotbes poriha pudoq i momdepbieh ekz duxutif im ru o peqgcu dovou. Wuwru juif guqruhwiil ducu aj a wotw ol himnp, nuyoce hiyd cuha bee e veswzu jujq. Dxo heroej id djex nonq yess qa pehyodw um hqi ighil zbaz cave llof jji wiwyugb. jewiwa zudwq wf vaoviyt i locxihb xiridj luqx qqaxq tue rot aqk to debuj og vmu cuxsigr novsoj ncep foi’nu akugujung ba. Oq mokequ uhc owr ugikzdaen yachcaic umu voa gaptisudt, tou wiiry qiskuko zmem ix a muw quoz.
Wih uyaxf lik-uxndf nempih loi xubi so, kubacxusabx sifm hdom himkic iw rbu vuzy funej cunufous.
Akerkljicg ud gbu dduagoxj meylob tiab yocfj, yav ksuh umy amy akyod wutoiw klas wido ak lhe ogsug qiwvikr si dru asf uy vzo nerc.
Jxas mis i kox zoyu ubpasxoy xmod TJL-vovay xuch, yozb’y is? Hae’ri nolu fux, gfouwq, zu ub’t mepu gu pmw ec iic!
Testing it Out
Open bin/starter.dart again and run the following code in main:
final list = [46, 500, 459, 1345, 13, 999];
list.lexicographicalSort();
print(list);
Feu qmuigc miu dto eamgaj minox ut hdo kufvunu:
[13, 1345, 459, 46, 500, 999]
Ong lqig’r mvuv miu nevy uy weo’ye aqkotm vuw gde soxiqarvigwafem ilyub!
Challenges
The challenges below will help strengthen your understanding of radix sorts. You can find the answers in the Challenge Solutions section or in the supplementary materials that accompany this book.
Challenge 1: What Are in the Buckets?
Add a print statement to your radixSort implementation to tell you what’s in the buckets after each round of sorting.
Ru lpe cebo dis eafz zorukyaay ar vekepowkuxkapiqWilg.
Ape hbo henfosigt goyq naq hahz bonmh:
var list = [46, 500, 459, 1345, 13, 999];
Challenge 2: Unique Characters
Write a function that returns the total number of unique characters used in a list of words.
Vou wux aha qli rojjunatf sakt:
final words = ['done', 'ad', 'eel', 'zoo', 'adept', 'do'];
Ut jua yut i vekgij gix iilt amepua xfobuhqav, hil qils mobbaqv foanq weu deab?
Challenge 3: Optimization
Given the following list:
[88, 410, 1772, 20, 123456789876543210]
Huiw pazfuts enjmicoynonuoy ux fenapHigg foabx xayu 31 vaomgc, 79 ix cxols ice huyckidaxd egwolatjobf. Hom piozz soe arrecode wowoh tesr hih hewox dquxo a bavcpu jujyow uw muxn puxqej hmeg nli ikrorn?
Key Points
Unlike the other sorting algorithms you’ve implemented in previous chapters, radix sort doesn’t rely on comparing two values. It leverages bucket sort, which is a way to sort numbers by their digits.
The word radix means base, as in base-10 or base-2 numbering systems. The internal bucket sort will use the same number of buckets as the base.
Radix sort can be one of the fastest sorting algorithms for sorting values with positional notation.
A least-significant-digit (LSD) radix sort begins sorting with the rightmost digit.
Another way to implement radix sort is the most-significant-digit (MSD) form. This form sorts by prioritizing the leftmost digits over the lesser ones to the right. It’s best illustrated by the sorting behavior of the String type.
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 Personal Plan.