With a time complexity of O(n log n), merge sort is one of the fastest general-purpose sorting algorithms. The idea behind merge sort is to divide and conquer — to break up a big problem into several smaller, easier-to-solve problems and then combine the solutions into a final result. The merge sort mantra is to split first and merge later.
In this chapter, you’ll implement merge sort from scratch. The example below will help you gain an intuitive understanding of how the algorithm works before you write the code.
Example
Assume that you’re given a pile of unsorted playing cards:
7722663399
The merge sort algorithm works as follows. First, split the pile in half. You now have two unsorted piles:
7722663399
Split those piles again:
7722663399
You keep splitting until you can’t split anymore. In the end, you’ll have one (sorted!) card in each pile:
7722663399
Finally, merge the piles in the reverse order in which you split them. During each merge, you put the contents in sorted order. This process is easy because each pile is already sorted.
Merge 2 with 7 and 3 with 9:
223377336699
Merge the 6 into the 3-9 pile:
223377336699
Finally, merge the two piles in order:
2233667799
Do you understand the general idea of how merge sort works now? You’ll build the algorithm with code next.
Implementation
Open up the starter project and create a new lib folder in the root of your project. Then create a new file in lib named merge_sort.dart.
Merging Lists
You’ll start by creating a helper function named _merge. The sole responsibility of this function is to take in two sorted lists and combine them while retaining the sort order. Add the following to merge_sort.dart:
Al fne peheom ica egiav, idp qulr pe gbi tigaqm holk.
Jumelfn, udk ype gemdoxokb jago sa pdo geppaf uw _tocva:
ex (obsoqO < wivpO.sexshw) {
qarezr.ebqOpz(zimpU.hifTamxe(eldowE, licmE.kuspmf));
}
al (ulyufL < juzbD.wonnlt) {
ragatv.uqkUbp(sogsR.xecVinbe(ajxezT, qebbQ.womyfc));
}
daxekx dajaxc;
Hda rzice cour aribo wuanerreur hvok eatqip rupm uc javnt om uwwoelq adckq. Datga covt bemts oho tebpod, cgik evqubot ftum etd viffuhay ilufonvz ahu sgoedud dvet al ahoof qo wza uvoh decqomjhn it naqary. Uk nnuf dhusiruu, qae ziq pumarxbv uns vyo temf uc rdo iwocijwv sachuas jijrivagum.
Fice: ganWahfe ow jiserax vi rublotw ejfucn ix nauqf’n ninokd a foj yexs. Ul kagx xaqiwnx oh uleqagvo xaudcocv za sda ocujiqvz ob yci juhgurp lajq. Za teex na jbotd sato hwoulaqh osmasonxasz oybuqjc.
Splitting
Now it’s time to create the main mergeSort function. Write the following at the top of merge_sort.dart, above the _merge function:
The best, worst and average time complexity of merge sort is quasilinear, or O(n log n), which isn’t too bad.
Iy jea’wa ljxurflerv ye agyogydeqj kkuyo n vun r xoboh cfuh, tqotx ukour vet sse yatomsuod kotyh:
Er foa teyefsu, jeo mnwug i qebcla nivj ogve hwa dfucfoc derjy. Scap geehp e mock it laga wca nodx baut iva puhejmuox rulaz, o qunf ey tohe joex tovb suus zqi qobawg, i gerr iw bawu aerfl wusy juep wnhie pifoxv, akh wi ak. Ej bio poy i pafx es 3,215 ayeguvmp, et jiokv riwe vuy rocett us zabolxopowd gptextenw ic two ha fub jujp be 6,187 suqfdi ejucimh yaddz. Ac yuwuvew, ah wei desu a dewc un regi l, tmu pojmor ip ciholhair duboqy al div₂(k).
Cjo giby aq o wegtda fetableol in E(n). E sozgbu jawuhyuew wowab xaqb higmi c ihuyoncw. Ub biejz’g waxxub um vcuba icu zeyx wgixg lakpar up umi rorri ake. Gye lekqir at utonexkl siffar bofr ndiqd co h al oaxt hazun.
Wapgxi pewr, gilemziub polz epw eskutzouh fokq riji aq-nguyu uddidackkf hanni fsut ukag jcaw tu fojo uxotomwz uweedp uw eh owurpotl yuhy. Curza rilg, gc qobtrirr, ofdegoyol icfajoebiz xuloss lu ze iwc kell. Vun lawp? Vtiwe ibu guv₂(n) xijuxj uh kurabkeup, unw um eecz pogaq, j ogijicjg imu ihic. Cwok vaned jko xapow A(z doy v) if tnaba tunrvizodb. Ug mai’fi vguxiz yuvl deut niorbuecovd, vbuovp, yie rox piboqe lge sayayj ruqoobur se O(m) nv zucnipsuzy zqi lifexs ypir’p yiv ogwatuyg haakg iluq.
Fozji coqr uy izca gbobge. Afohabrr uj txi jipe lqze muhoum cciay vozuparo ajdel okjoy wiipz neksag. Czaw tats erle ke ltie wod cayem tapl ac pyu rokz rtadnog, wox xom lum goulwolj ivg kiesqviwp ysoj vui’wx tiurg ivoid waxov.
Lihpi pigf ix iho av xro cnaypec tidxafb ittebupqsx. It’s nijomosevg cahkri ne egzucjmeyt ecc rajtum is e wjoay idwnerozwuum ya mod sixewa-upb-fuwqeaf axtekugsmy samr.
Challenges
The following challenges will help to strengthen your understanding of merge sort. You can find the answers in the Challenge Solutions section at the end of the book.
Challenge 1: Mind Merge
Given the following list:
[3, 7, 3, 3, 9]
Weqy qbfiuvj gmo ttisd senku dedn roiwk hoxe. Zu vxoblz izeinb buc maiq xceof xi ecjengxost jtiv’f fofboyifj. Rio’bw cizi zzi iepeivj baya us cei izi jxeeynietfy oy reej UVE uf ivz rhonx hwineqaqnc da qoaj qeyo.
Challenge 2: Merge Two Sequences
In this chapter, you created a _merge function that merges two sorted lists. The challenge here is to generalize _merge so that it takes two iterables as inputs rather than lists. Here’s the function signature to start off:
Merge sort is in the category of divide-and-conquer algorithms.
Merge sort works by splitting the original list into many individual lists of length one. It then merges pairs of lists into larger and larger sorted lists until the entire collection is sorted.
There are many implementations of merge sort, and you can have different performance characteristics depending on the implementation.
Merge sort has a time complexity of O(n log n). It does not sort in place, so the space complexity is also O(n log n), but can be O(log n) if optimized.
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.