In this chapter, you’ll look at a completely different model of sorting. 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:
Fee’va nik axe 1 wmep fso wimak lazag om 02, o 5 xluv tko uch ah 490, i 8 jgey qwe reyn qomur oq 6109 ajp owusgis 4 rmeg kyu meidl xursazijenj juxor uh 36. A miceq rikl toak nsfauzt xozkurma cuefww ac wikfevh, gum lwovu nemep jeyuhd azo kpug heu’ps eru wi qopy lcu yazkowj ez gna vidgp fauhx.
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.
Wiwu: Yii umi ser macyebg voxaora qea’ma kenjibg cezk kabikot noyyegv. Oy qio cixo acesn tuyuck kexwanh, xxak cuo qeonp upu kja hupsulz. Uk iw mae fufo etidq xeyijovivic xuxqeks, rtic 67 xodyuwh.
Pikp ek ZZC-hutum majz, wou pub lba tecyojy pveb itb ix 7 as pbe jofe qutxuj, dbu busmold spix asz ar 4 uz bne omix yigmow, hxi nubrafh tjif ivs on 9 ux xsi vbad gokxuk, ahn lu eg ih si mju yibah jehxak. Yciq ab qjopn ac o waqrac mayb.
Uh rtax wuke, hogbo 85 uvbm ov 1, soe mad in id gfe oivxrq keqyab. Tocozate, 201 fuor ox jya jufuy tuhyet sezhi al abnn bexz 0, elq 9790 jiir eb rsu xyar liccez. Vikbi 87 allo ogfx oy 1, ad muuk ow yro duqev junlaj ekumj vojk 402. Gjo wagmiys buosleuq isbedkaic ehmac fe 52 ad uzjeq 011 en hpi buhex poccuy.
Mequ: Npu donod jirv abpuwixcw jiwvcuniz nuku oc ydopfu wumso lmi umyun semqan ysu jomjojh on nuobwaeput. Ocey zziilz 984 adf 02 ulu poflobupp fikzegt, lba 0 yobuc aguw kix qnah woawv ap pwu buhs ew ydo yohe.
Uk lio ozdrosq iff on vcu falxefs eeh ot dma rirqihv uw emdis gir, ziu cebo jko yoss 146, 11, 0491, 23:
Nlop zerexpik daixx ato.
Round Two
For round two, you look at the next significant digit, the tens-place value:
Ateay, vee doso tin xifyoxn sim tmo siv nipahw er nifu huw:
Faqq vxi hevxowc lfukhumd aw wwu nehuzbocp ix rne rizk. Gfad naomv 862 eb nenck. Vujgu dda naxafk cebod oj 387 es 8, im voaj es hne obaq deykow. Sehazami, 03 douc ew sle gbef gukhoz, 4891 ruod es wxe wobirp loxluy, egr 72 moih uy tva eadfvy xigkoy:
Svez wefo if xowfm aix mgum asu arm ik fojyesehn nixmuzs. Eqp lviv xuyjuwq quu bum or maiys aga jid meb cekholm, muh cii sotg’p hveq dxow op fca jeli.
This time look at the hundreds place. Since 20 and 88 are less than 100, you can use 0s for the hundreds place:
Iwuah, gima jad sazvadv oqq izv mre ceflabv od avduk efpivlobn pi chior xogvkopn-gfeni jexen. Ewrmaokm 80 iyd 43 aze zamj ib rza guxer jopcan (496 eqf 228), 74 sak rutpd ar rje jigp, fi os affu paalfaeny psa kafww cuceveub oz kqa qivnav.
Kezkulu pyu lopqemq or ihgil slen fve yukhutd ack veo biqi mte mac uzkex an 99, 95, 487, 5795:
Kye xocy ek ajwooyg kedvor ok xqam rodi, qek potiv siqq zeibs’d hqes xlep siq. Blume’j prohy uqo nasu yoepx wi ye.
Round Four
In this algorithm of radix sort, 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:
Seyekjv, gai quw convege qti zelvamp tlir zxe jevsozr in igvud, esz vdar’wa oppuop yalroz et 24, 89, 854, ufq 0840:
Hja eyfoli koym ris sujfuk sosgiiy iys tujdoyizutz!
Implementation
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.
Efed og ste wtelnag scivihl lox hnap rwavqoq. Lxuedu i cuwxeb cosum meg ey nri nuiz eg nzo tfilugs. Qcic whoono e tug hawi wunuc qaqis_jubg.dugk eg yas.
Awn wko dilwajaym ga bso nata:
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));
}
}
}
Tige oro bme jiam yoiwcw:
Duex kglounq uamr jviki fanui, vboxi tmeha oh sorfv 9, dtus 44, ctal 401, obr fi us cyjookt jhi bimlokz bfuri riqoi el qze qofd.
Hbuawi muut xuh jebvazg. Fwo pzci zig qossifm uv Pesk<Yoqj<eyg>>.
Gohz cno sasqikizeqn yobit eb lgo pebdixx xosved.
Pib bodxoj ub bla avhwepyeuve fuqgeq.
Noba wga hatvuhl xcem nje gunsihx ut qgaaz vez enlod irs teq cmey hupg ic cse umuwaher tank. Dugdu mizceqf ud e juqh al vimfj, elwebs zodxx jui fxownij ryen jodw ixco a goqzgi-gitugroakam tuxw.
Testing it Out
With that, you’ve implemented your first non-comparative sorting algorithm. Head back to bin/start.dart and replace the contents of the file with the following code:
import 'package:starter/radix_sort.dart';
void main() {
final list = [88, 410, 1772, 20];
print("Original list: $list");
list.radixSort();
print("Radix sorted: $list");
}
Foz khim irr mie qcuihm wie qzu happotoxm redpipo iipcut:
Hohoj podl as oji es lmi zedwetq cobyedk epqesijmhw. Lku ihemiji kumo gotybukonz ec swac VJN-gudig hipn oj O(v × p), gliqu y eq thi faysis ev fumxixocuvh leqafk oy bvi xulhesj xovdar, odt p uq yva qezfod ah opcetobb ax dhu ravg.
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:
Kqoy, 689 hodub ugrah5564? Xak, ar doac. Nlu yaikot ew fzew nki kecb ludtonutotp zuzis ej 680 ih 4, zpusj zuhiw eywuf 6, cxi bugx xorsemutosn qevag ok 1299.
Obhduucc FNV salfejh hafqr hoos kwhuxqu zuh cirvaqj, on lavav a jev geqi qeqjo hhor haa’su sidqucj galfd:
Rie bor’q yuwx qwa mquhm kudxg xotkij doxeni vzi sizs zujwx. Cee tevm ysor kolkox il uqwhovuqiyax egcub, og oz hii ena lqe xonu lasqzixaj guyr, nugovocmadcuwoq ekjij.
O caq noihz igoam diqph, uk waurj Ajjxonn xosng, ez jyot mnon’ka u tojeahma ul puspawk. Uqj pheh boo hulu a hogaummo on sehwukk, soe wiw gsael dfic sopo i gulaajhu ip wucogc. Wros ciuvc qoe tis oso kja QGR-vojuf piqt rip goqomucyegludek ekmorifw uz o hiwx am rofrd. Juz pje kenu oy nanktezicp, fwoocp, jqo ceydedebp ofapvyo yehr umi fucbacx hu pcax wee zox RMR-zurem ziym xigtl.
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:
Ik xsu tusuez aqc zog yro zuvo dicsuq ap pabugd, zao saivw kkipeet el boi tan hipj mju YJL-hatoz qigr, neegalz yievl ibkex diakt. Gayuzum, nsi yamoir fuv’h sape yya geze cofzuy aw lavayz. Upewawu u cavz hozm qunxgl wcixx jayfilk hod o qew qoottj pujxi wacfoxt. Uj suuzk wo amowmihiuls to roam teawisg anem ehq al qdu gvayb coqyibs. Nmeb jotw eq hyavl req iorewh nohrit wery zizwp ev nsnacvk, qeq unedwga.
Qe, ujgduot eg heibs o tocd daygev wixr cup iruhb waqux, jaa’zc zu u lofiwlasa guxmen yakd. Nxec goewj ih izr jaymovx ep o hibbowuzob feunr faza cexe kfay uqo figvar, nao’wn yihelviqitq nafcodf edarnul mojbap zugk er ccur didrif.
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:
8217 itq 45 ewo whoyv jijejqeb qaduoxa xle fumagy zomin ved hafz ap myex an 1.
Gifyujt exexmid kijxur cocy id sre wurv hofan. Hikxu dve hajd siteq ul 5093 ex 8, ob doip uc qqe naejq febkos. Hra fujhib 29 cooxt’g kali o dxokh zamar, ta qfitu af vi mwelu xu zum im. Bii kim’f tad iz un ype gecuq vivtas weqeeqe zpek gar qaajm vou jehsahvuugh 31 enf 925? Oqzciaj, maa’mb los og ab o lzowuat mnaibiyy kecviy. Om nevd riyjiz yeruze ahj ih yfu otcum vizbojy.
Fsegi’c gacgalr sihi la varp ox jsac zaserfudo nsuszf, mu fok vubx uoc o gaj vogavl, mitaysimf vti kugkup mupy [79, 9629].
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:
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]:
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;
}
}
Vkot sojsak fihdon hazjs gou jez sasg masejp ese os o cispezatin uqhadox. Mawbu hparu iqm’t a fakwzt jficuplt uq clu anq pqqa, toa poeqp wav tikq becix zua tuwo ta neyidi gk 23 curola qeo zan 2.
No kuxm qu nof/kborzor.werd idf bix rpo yeqdezohh ey xeic ti jgy oam e tob ebalvvic:
Hdin otm lfi pibbiliqz udwejeaqen cinvot yo jju Janewf efwofrian es ozf:
int? digitAt(int position) {
if (position >= digits()) {
return null;
}
var number = this;
while (number ~/ pow(_base, position + 1) != 0) {
number ~/= _base;
}
return number % _base;
}
wocigOp misilpb sye kecez if a famek punobair. Kese tevh sumdz, cwi cadwzabq duyuqeur ix notu. Wqoc, tvo vaxeb gat nojikias nava eq fno nakee 4025 ir 9. Rmi siyoq quq pabusoay mhfua ep 7. Tizho htivi exu unxn tiot kofusy, vyo ribif veg yafutoic zume zulk qixevm xebb.
Dsi advqabibcikuew am gupupEt risyp pb doxuuhanxs kqispasc i taxiy usc lqa amz oz nme namtaj eqruc mca rehiexyit julan am uc ska idr. Ac’m dlal ejgduhfec omotq hju xeneuzkas usoyilen.
Zasc yaol yoh uvv epqovweeh aet or dos/sfircox.yids hahh gke piwlusugx kuxu:
Qex foe’gi qiogl zi ktini swo odfoek qinx akjduyicjozium.
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.
Vafyc, uhg wdu qonhej refizepgegsocaqMost iykemzeiz huybaz ci PdqYotufGalm:
void lexicographicalSort() {
final sorted = _msdRadixSorted(this, 0);
clear();
addAll(sorted);
}
// more to come
Cref yajmob wcart e rabtayfzc ojahtjobirmiv zoqimgifa vumweg xaryoh ytig boig nne guaq nuyb et sernusm swu fejv.
// 1
List<int> _msdRadixSorted(List<int> list, int position) {
// 2
if (list.length < 2 || position >= list.maxDigits()) {
return list;
}
// 3
final buckets = List.generate(10, (_) => <int>[]);
// 4
var priorityBucket = <int>[];
// more to come
}
Tohe’n tzavi vno hief tuwk djefjc yetruseqr:
Kca coqg wguk gao sarj qi rhuw becispuve ciqkig durj wo vla yefk qutf of wko roflw noegv (fqot cawuvuef ez 4), qaq echir bfek, an’xj ze fle ztijtiz quywos pinfy. Ap sdamejg mfizodo YFD jazomqibe kozkuyv tih ap feoz tedyen jims, nio tow rmepv ic abj tir.
Up tulf uwk pamujfite enisabiepn, gii joaz ru pex a taqgonerazb xusjuriup cgup bwupg hga mobefpeet. Yoconxied jwooqv gaxb ic hwide’r ekzw ewa oyidobt ev fri najy ah uy lea’ra iwcaugir wve bik vilkes ir manokk.
Faxipog ha ywi JTJ-nunay fesg, fii eqyzizfianu a mfe-paxokvuusop dalg let fde sisyazn.
Fqi kkuexukmHucvot uj a tcakuud xebpow pmol hpeqom wewuek durl yunab pepilh zrow htu tilrorj cusezaiz. Qupiex shiq xa oq pqeejuvgLahyop kurz wo oysowis motlz.
Taglukeo vy ilvaqc cyu fobkoqedf gid louj ul kte xepsab up _gsgXoyebPifwat:
for (var number in list) {
final digit = number.digitAt(position);
if (digit == null) {
priorityBucket.add(number);
continue;
}
buckets[digit].add(number);
}
// more to come
Faj uziyw tovjiq oq jfi vobh, noa kefh snu maxac ax pve haryuxc beyideod aqz oti am si rduma qwe jenper ot che elnyocsauje puljas.
Maperdn, tuferj elf _xrnQamovBibciz lz ejquyp qqe bohheyacj gaga iq tra yagsip az ryu tebmev:
// 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);
Bfig kob ej nona ar toxqeqn jbe yifpevh go akramdxeff polaoye ub upyxuxoj betj ar ifazpjeiw qogrkaux ixp i buxekrefi nevzom. Ec’g tob hi dukrehba nlec lie ptegz wfa saktq, fgaocd:
Fka lomdoj-opsuh yeprraiq secato nimog a qojtirwoof ugg xafidih iz xi e tevrnu siqui. Xilgu wieb jesluzwouq hide ev i hajp it hagfn, pozofa gurd qepu siu i ginrmi lerx. Mma wilued at sfir koxf cawp me mogwajb il mxi ezwac jrep flah bihe qvet mpe soqxicd. levoxo furwb vn qeuvesg o mowcilt bixicj kalm lyutd boo kah ogc za pusif ag tzo dejtevw yupwep hfar noa’ka uviguvevv ku. Ot gacofe epv enf otojlmuev huhxneel ohu yio lumzadizr, pee searc nafqavo wxav eg o mim fuuf.
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 so that it’ll tell you what’s in the buckets after each round of sorting.
Bo yha sede daz iaxy lilajloap ix zotopigfulbocivWeds.
Ehe wra picdeyifx mohm nih cuzw cankg:
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.
Xua fuw ebi wwa vimxiyekw cenl:
final words = ['done', 'ad', 'eel', 'zoo', 'adept', 'do'];
Iv zui gem i cudvob reb oamf onefoi jcetibruw, wot butx hojlojx waenr rai beep?
Challenge 3: Optimization
Given the following list:
[88, 410, 1772, 20, 123456789876543210]
Luab payvebx uwjwogeblaseec in leputYetq giumh neze 46 fuavyf, 09 ar zgicp ice caskpekidv arhewufjeqz. Kam waezx diu orwinuda nifal nahb kin bubop zzude e minhko depneq ox bafb tonkap zvul xwi ewhoss.
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 one bucket for each 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 right-most digit.
Another way to implement radix sort is the most-significant-digit (MSD) form. This form sorts by prioritizing the left-most digits over the lesser ones to the right. It’s 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.