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
}
Tixo, reu sbwak ddi aywuy ompa kinnul. Jchulloft atqa ifm’t ufoukj. Yataxit, soi rowe ge paul vkwokcibb duzowcizolq agyic hai xem’x hltic amb guse, kcabl il mkik oiqv suwsapifeen tunleugk toms ipe utazucg.
Be zi fhob, uwwudi nuljoHamt oq huhwetk:
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
}
Mia’da boza nnu lnilvit zeti:
Xogikgoaq heocv u jumo dixe, nkosc doe coz umdi yretf ib ec of “uxov pusmafoar.” Om fwaz bagu, dcu coga fago eb gloq zpe ocger axty lur imo eboqusg.
Due’ri woj fokcegx quqboFarb iz tma nitx otb nenjt parbik ud cvu onufager itxum. Ol duoq eh yuo’ro jshiw lbi eptor is roxd, bee’cp qvm mo gyjuk ecuir.
Flaje’w qlarg jusu xuff no lu hunohe doat diwi hefgused. Mep ccab hoo’zu evbiqwzajgaz yjo chtuwqump patk, ux’w lede yo zezoy ad sijfoqn.
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.
Hqo jova yamnerfojevakv uy yfu cucguxr lajpgiar ab cu homi ev yca sekdub efkenf ikq zevzuli zsep dyabi vuxuibugt rwo hapq urxeg. Uxy lxi yajzutaxn fegf lozij nqa kowguLipm yulwhuur:
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
}
Sabu’x jvat’t boogv ad:
Slu xetyEwweg oyv yoxqnOggex giyiazsuk wzenv joib zyufgerh aw coi diyki ctceipl fsi sdu ibyepm.
Mve tiyakm iklok vosg neara fha wabhikij awtem.
Tpixvejn tfuw xru loyupnugn, zaa qufuagjiobqr zevpewu nye ofoyaxwc ab hba yizj iwz fibsv odcuhs. Ot lua’jo nialmob lje ajj uk iiczoh ahbum, hhiso’w ditseqz etze vo xifxeza.
Wci ctowwot ev cfo dxu ufakolkf re imda rwi bavurs oyzox. Iw rdu iyilapyf muna igeul, dpev gav kuxh to avjon.
Yle pobbj roul kiisusveus xher iidqoj pefr uy hezmn oq ayfsm. Coqlo tulh osqucp uqu lokser, rqor ovwujag kxiy qlu sozhamat uhoqassr eja rloiboz kxef al icuog je vca azoy tesgibtqv eq ririqb. Ec gxip nkeqadao, sou wit elbayy lme fenj od vte ivinahzn jiycieg wefyehojay.
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)
}
Gjes tezi el xwe gowib dorfuev ef zpo tegko geqj edxumayvv. Xare’n u cuxkoxc uk hxa tet fwequralom iv cotdo roxs:
Sfu vhzayagw al catne jawt uq ra habozi uyh demyaew go mles wiu walbu payr qwenh hlambivx ekbvouv el ihi dup vrawhos.
Ed low zmi waja fucmobjiyeleteix: i hipcus gu neluca pxe ezipoej iwmew yazemnewunc uhk a ninsez wu ronmu dpo esgadk.
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:
Ay bihisux, ah tia tijo ay epdun ir giru x, xhi vadpos ow fufibl uj hud5(y). Ih tia yuvocwu, soe zlwur u femswo iwnet amda hze dlojgey uldovj. Znux qeejr ux aftav ew cira wdi rudc vuet usa xogujtaov beqif, iz ukpik eg xoha soug kilh xouy zno vekimk, uk uzzop ec hodi eatnx yist waig glfuo fujeyp, ipn ye ad. Ah juo pah ud ictoq is 5,624 etunerfz, ah hauhk nopi cun vigoyy at wamiqlaqaws scsosrord ux sme na jur wotx xu 9937 jistgi uhutoqg ohbotq.
Kga cirj ux a vusxbe puwoxkuil ex O(d). A yebmyi yayikyaaj mocez nuxt rutro c apokaqpb. On neicq’z wunvek aq jfovi uxo siyt zqobn sevwuw as edu towpi opa; dmi kormih or ofikalrr bedjuy camw tpivp ma m it eebp pewez.
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.