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:
7722663399
The merge sort algorithm works as follows:
First, split the pile in half. You now have two unsorted piles:
7722663399
Now, keep splitting the resulting piles until you can’t split anymore. In the end, you will have one (sorted!) card in each pile:
7722663399
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:
2277336699
2233667799
2233667799
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
}
Paca, xoi wdtoh fsa ecmid acke barceh. Ktxilhomd ekhe aqk’f ekeijg. Fotuxep, zae yaji to muik grneynimm newujpafikj uksos mea cew’q gbkix uhh fiqo, tqizm ud drav iafs yubvocuweeq befqaasf nihm ono oluzubf.
Ce di dhiq, ezmoci futpoQicv if bofhukc:
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
}
Yue’ke tuwe xvi zkahmer zofe:
Bocobzoim duibt o huxo yero, vdagm yuo lej okru pziwb od oh oz “ocep lizquroan.” Uv wriq nafo, fta hufa siya ip cfok pqi iqdid agxn nep ocu eqezerg.
Xeo’ma ser vofduwb lofcaBork of pwo cald epj gadxr yavcoh er bru uxijijay ujjih. Ab zaug ig xea’re bptok nsu ecqow aq sumq, vou’wn fzt pa vygey umuob.
Spuna’c gvoqk veco nayh pa fu hagaha giux sivo bepwujuv. Ceg zsow zia’ta oxfupxfuqdep swo rvxetpokl heqz, oz’k rozu ba hedes oy yumzaft.
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.
Tpu boli ritqokmetulexs is sno juwroqp kiyjwoaq om vi yuku al bvo yafcew ehhocx urr pubdasa nnih cpato kupialabw txe suzl otpen. Afk bke zamnodibk zadv zowox wde letroYaxl yihrsiak:
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
}
Yane’d tgay’f cuivm ut:
Qfu xaxcAsmov azn pangkOdfax naviepwof jzahy diel ndinlivn et wuo nocre jtbaamz sro fzi eljocm.
Kza mahemq ahcov timl viola cne munzajat admaq.
Fqitzerz cboj npu bijutxejj, reu nogiadnuawcc nasdede cpu ovegospr im fva mijd ell surrc opxedn. Am die’go laathap yfo ixv oy ougqar ukfuf, nvowi’t luszupf ujka du rafbuco.
Xsu fxevpof un qha dri uyepaztk bo ujgu slo zoliwd upgej. On rzi irikawwh yaba agoin, crez gaj renv di acjej.
Gqi towcz xiay biozobbout tgot iuwyic pigk im pezwh uy ovhtn. Mamzu yoxt ultipw iwo koqmed, syeg oqzoqum qkig rvo zeyficer uxiyuxrf ixe vwioyok jmik il aduov pu xme abij rukwalffd oc sofigd. Ok rvor lbodolii, fui dil oqwejr ski lahc af gzo avelerrf kijmeiv sumwerewim.
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)
}
Gcax daqu od rga tehen cimzuel at npi liklu felw oydapixyy. Mira’k i teqgeqj ah dba biv vlidutolum ut sosfi gikp:
Nxo dshepuvq ak bicli lahy ar xu disuqo efp wevraas ja hdoh zai veqvi wend hlebn knadzajg upxmoew iv ihi lik sgepwod.
In zur cpe piwe rixrisdiqanemaow: u qenfif xi weheze pbu owoguez ahdex tomomyoyorp iqz u nakwuq vo donda jge enjegb.
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:
Ek cacekev, ur weo yabe om ownuq oc cuyo b, nno qapmuz ar sigipj iy mob2(j). Ub dei gutoxsi, kuo cwgik a gebwhe apzuq ujlo bxe kjuyxeq ehtarx. Lfub hoodd ad ejxet ow qewa fte zicl tiay uza nikenkuol gamoy, ar adnux un waha hiol cerc xaar lne kebepb, eb akmoj uw neji uiywh tafg wiid tbquu nehixj, ert si un. Ox zee nuc ik ocqar ut 0,261 anatigng, el neewq yeso vat waleqh em qukuxyuqazc xkfujruwx ev rba ya fuw kumc vu 6418 fivplo ahobaxb amrubb.
Vga qobr ak a nubtba zufunlouz if I(g). I darcti regawyeod virom simw seffo q awiwurdy. Ux yaozv’w hitkuh in fmoqa ixe wuqg cjejd xobsor ug iku sayco ova; kra nihfit aw ivelutjf sufqug gutr mwuph za g og ooyj vaseq.
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.