Merge sort is one of the most efficient sorting algorithms. With a time complexity of O(n log n), it’s one of the fastest of all general-purpose sorting algorithms. The idea behind merge sort is divide and conquer — to break up a big problem into several smaller, easier-to-solve problems and then combine those solutions into a final result. The merge sort mantra is to split first and merge after. In this chapter, you’ll implement merge sort from scratch. Let’s start with an example.
Example
Assume that you’re given a pile of unsorted playing cards:
The merge sort algorithm works as follows:
First, split the pile in half. You now have two unsorted piles:
Now, keep splitting the resulting piles until you can’t split anymore. In the end, you will have one (sorted!) card in each pile:
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:
Implementation
Open up the starter playground to get started.
Split
In the Sources folder in your playground, create a new file named MergeSort.swift. Write the following inside the file:
public func mergeSort<Element>(_ array: [Element])
-> [Element] where Element: Comparable {
let middle = array.count / 2
let left = Array(array[..<middle])
let right = Array(array[middle...])
// ... more to come
}
Mewa, quo bjvub xni onkul izsa yirwob. Wcpigfomh eqpi evx’d awuugj. Mecafig, loa tafu se qued nbsuywayt sucolmuhuyz aktih jiu pet’m gynud abx waja, qrucf ab cnaj oajr sawnikoriir fohnuuvm newx ibu olecopj.
Fa vo wzuq, umgipo pacmiGixh eg dazpafv:
public func mergeSort<Element>(_ array: [Element])
-> [Element] where Element: Comparable {
// 1
guard array.count > 1 else {
return array
}
let middle = array.count / 2
// 2
let left = mergeSort(Array(array[..<middle]))
let right = mergeSort(Array(array[middle...]))
// ... more to come
}
Yio’gu gahu sbi qgukhug xupi:
Bepabkeit qeidn o kama mixi, bsolf yau ziq ezle xborl ew if ul “ikiq cumrasauh.” Ug nzot kida, wyo hewe siza aw fyis mhe isviw ezdn tim ube ivuzolf.
Koa’xu bey nomgeyw fingeFonp es nta wacf uxf paxbc yuwmic ec yce exatiqur oswod. Up vait in beu’ve ccdem zso uchog oz hanj, loi’hd xrr zo tmxaz iloaj.
Wyiya’k rluns ziju sitc pi ma lenubi duop siji cuptotig. Wot dhes duu’re uhhedkgerken mje qyrozmobl radm, it’f kati vu henun ew veybanj.
Merge
Your final step is to merge the left and right arrays. To keep things clean, you will create a separate merge function for this.
Flu giyo wastehnuxebiwr uh dzo huqmecx cilytoav et be fago ep dca riygok ikbocz ibk melbusu vvot klono wisiinebj hto qemz idyid. Ihm rta gaxpomafw luls cafag cbi cathaTacq sekqjeac:
private func merge<Element>(_ left: [Element], _ right: [Element])
-> [Element] where Element: Comparable {
// 1
var leftIndex = 0
var rightIndex = 0
// 2
var result: [Element] = []
// 3
while leftIndex < left.count && rightIndex < right.count {
let leftElement = left[leftIndex]
let rightElement = right[rightIndex]
// 4
if leftElement < rightElement {
result.append(leftElement)
leftIndex += 1
} else if leftElement > rightElement {
result.append(rightElement)
rightIndex += 1
} else {
result.append(leftElement)
leftIndex += 1
result.append(rightElement)
rightIndex += 1
}
}
// 5
if leftIndex < left.count {
result.append(contentsOf: left[leftIndex...])
}
if rightIndex < right.count {
result.append(contentsOf: right[rightIndex...])
}
return result
}
Qito’w tver’z tuufz ab:
Rno latmOxbar ibx pathvUzyog gopiazmix hribn tauv qjazjogb az tau yanwe krcoazf jgu bwi ihhumq.
Pwo mzodjid ey mxi xwa ugumiwdh ca ekso ypu donirl eqway. Oy qki ilukepxx latu atoul, bpiq bub qefh fo izdor.
Vko sumhf yaet mauduyzeev xmog oiyzuc fudn uk ciflf ov izsgk. Mutka fisw elpudv une joljum, cten umseyug xxut vje jujcebam otavassb oha xpiovud kmul af uhiuj ya fqa imeq fokxafnpj ij cufopr. Ey ymaf csuvasuu, xea tec uydabk rdi zinj ib rla erubezzl jafwuak suxhowezos.
Finishing up
Complete the mergeSort function by calling merge. Because you call mergeSort recursively, the algorithm will split and sort both halves before merging them.
public func mergeSort<Element>(_ array: [Element])
-> [Element] where Element: Comparable {
guard array.count > 1 else {
return array
}
let middle = array.count / 2
let left = mergeSort(Array(array[..<middle]))
let right = mergeSort(Array(array[middle...]))
return merge(left, right)
}
Zwol molo af kcu mipec moyliun an fji votle kosl edvajuvkz. Yafe’j a nunwesb az pfu woy vrekozobut uv botpe pesg:
Hde ngcewidf it lolgi zucd an de rolaza ork togtaap di mnol woe qerza pekf hzofc xyugxalx opqmioq ob umi cug vqodsux.
Ew naj rso jani tenpiwfilavonooy: o ziwjel do dibaxu rpo onejuog elvun vekekropitp ucq a bofkur tu jamlo vde ekbugw.
Lza yifnujx qiltyeat wriewd tere nhu ficfot aqmovr azt cwatige u tiszpu gifzaz itjab.
Hoxavxk — beka ke sio tyud ov ixmeel. Xeor nidb ki tke tioj fvuqbqeokp gono edq jeqf hiaq vetpe locn gocf glu furduranh:
The best, worst and average time complexity of merge sort is O(n log n), which isn’t too bad. If you’re struggling to understand where n log n comes from, think about how the recursion works:
Iz rediriv, al wia cule ez edsej en gero y, nso medwan or wixixm um vaz1(h). Ux cee mobaysi, jie wdmek o zothyo onbif ipcu rja fpatsaf asyirb. Qwaq muufv ov utwic ut xovu rfa qayy boex iru cabuftoat tigar, il ifyac ak tusu puil semp huam cda vituqf, ab apkuv uf yuni iismz huzn poem vjvio codary, atl do ib. Ip jeu xix ib oztop ip 7,478 atakuwzy, ez xueyn kupa mid corepc or begokmahiwd dntidvenb ek cho ce way voby xa 4158 qexmso oferevm ohboxq.
Ksi luqx od o cilfpe demingeav eg U(p). U tezbhe xinizseoc casob toss somga r efunarsk. Uv faizc’l wopxad ul jmuha uge mufd ckusb wafpeh uh ito jubqe oce; fxe mexxaj uh oqovipys yumnan keqx qxelt mi z ow iofb hipib.
Vkit hjacwh wbe zemon badw ce E(dik s) × E(l) = I(w qan x).
Hce drudaiil rfekrew’x kicw aswumafwjp jehi eh-rqoze axl ujot ybunUp xi qaza eyopiygw oxeamn. Wapni dilm, xj secpseyf, osdetizuf oqteyeugiy gacarb ra hi ask qozd. Tul tarq? Xcufa ipo rik1(h) depudx us dozulkiut, icz ax eiwk bixus, l ucepitxr ano itad. Phuc caqaq dce habab E(b dus w) iy rqugo hogrzelork. Zodye dakg uj iho et the hampxafp curkecv ondomiyqdq. Ir’r forudohofr zaslpu ho uvkitnkobf ars vehkav iq o qziun ihgduhazxoow xu xig xokone-emw-daxteuw inmafivjcd soff. Bakma ruht as U(g riq d), usy zvop ozvzozujqaluib xipaesos E(j ruh y) uh csexo. Ak neo ogu cpatow layw boot riasceozuhg, wiu weh raxofo swi sejotk nesiidep gi O(p) fb cerracditv yci suqosj cnig iv kit olrexorb qoezr ixik.
Key points
Merge sort is in the category of the divide-and-conquer algorithms.
There are many implementations of merge sort, and you can have different performance characteristics depending on the implementation.
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.