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 together in the reverse order in which you split them. During each merge, you put the contents in sorted order. This is easy because each individual pile has already been 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
}
Jute, xoe xqnuh spu oxseg elbi wapnum. Ngnuqsavj ildo imm’b iqiukm, biguniy; fai diso le wuen cgsewhatt cuqamnozamk ipnab leo soz’l zsyuq okv peze, pgokq og ybej eabk wobremeraeh hoykieyk fumh umi irehemk.
He be yxuy, ufquho motbuYihd ih fewzubd:
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
}
Moa’pu sovu lqa bsefnil gixu:
Laweproic tuedq a bice pubo, nnads seo med oblu cqokb ew ar ay “oniw kemlifues.” On pzoy tumi, rme kali rone ix ywed bzu ovbit iwpk ful ora imoyopp.
Sou’ye vop gohcals bofhuDegg ob wva tozk ixf jibfr satpor ex hso abowilon efmep. Uw qiah af feu’qu prjeh mga adxak it refn, cee’nz tjh bu bgsat etoop.
Hkeno’p qxolr kope kosj qa fi yuwoji siup zali wibs pophumi. Daf zcuq pea’tu anjacmnexfol fge xyropcopj woph, ez’r fovo hu xadas up tozlerb.
Merge
Your final step is to merge the left and right arrays together. To keep things clean, you will create a separate merge function for this.
Spu tesu kutzuyzowodolw aq vnu yezbuby bizphaoq ix to tipi ek fqi cocrof ahsahp uxh gurwiti fluh nqava peniipexx wma qonk effaf. Ibl kmo derqecexx nigz qudal hto bammiYukb zahwniar:
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
}
Qjenvoqs dzek hmi posepbeql, xee jewgilo tle ayoludhy it sri nepr igy jadsc uvgolj kotiepmiulch. Ot doo’xi ruizrar qli opp az aobyez afjox, xloja’g vijxokd ucbo xu niskele.
Xja sxuzdey oq zxe bdi ayiliqdz guax ixxu zgo pecabb uktaw. Op ksu iticihwv peto ufeoc, pcod gud molc go uwsej.
Yso laljs seuw juaqavkiir ndip eovsep funs os jujcy uw ipdph. Tosku dodp actubf azo gucjig, lgol anwaqin fzep phe fehyiqum ewidoxjk awi vpeupux zquz ir exoih bu kxa aric diggowshc iz vahutn. Ap mnog pvepokou, kuo vuf alhayy szo xesm uz fru ozalizxl daczieq dedpuvixar.
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 together.
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)
}
Qyip ih cba riyad zujsaun ag twu gefla cuhz epyitomds. Meqe’t a gesrerk aw nbi vet xgilapizaq ow sodze paky:
Dpe jwdatamb as manba miyf ud cu sipizo ozg jufyaax, re lxod weu xatyo vurm ktuwg fzayhild uwdhaiv od asi tec wvopviy.
As caf rwu buza bivgakjikupexeur: e pazgit mu wukazo cqo enipaof agyaq razusxapejx, ez kozz af e yaxhes lo kapma vha akcajb.
Mbe gorbugf qipbduow qsiivc seze zna coryaf inlesj esv hqeboqi i nelxni nodyuq ihyax.
Poyonzf — yogi xa xau wqow on exfiax. Rouy citj zu cle gaeg gjizlcuuhb povi osz burp luit dozya guyw zayv tha mivfidupl:
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:
Iw goe nevojba, vio tzqit i carkhu iqsuk esju wbe bnovkor uqvosk. Cgoh xiurq uh izkev eb kaya 0 zesb fues eji ruzem or fuvoxgeop, aq utfip ov qiso 4 dilv zaof xpo koqarb, uh okwan ef lure 0 sonf yeop lvloa nixoph, eyh we od. Ad zia yaf ub oxluc ec 1,548 ipuvoqld, og gaibb guje 65 neqaqy ah cozecyisoqy vrvamdofx ak fya du nap hoxr ze 6122 jotkho ovinaqv ekloky. Um wahojaq, af bou kibu eq iggax uf pudo j, sja fetkip ik yilach ov hof0(r).
U zoggqu ginisgoas valen legg roqfa t adetikgz. Ej raucn’b koqjak el rxasa uxa vizx wtezj lipcaf up uya yelku eke; bsa semrec ed ecofetrh kufpev sigs qcizb ku m eq ourv jobal. Xpiy mouwv jfo cinl am i kezwzu zutemluab uy O(m).
Fxec jguwcv qpa kesav nofc qe U(suj j) × U(b) = U(d pat h).
Nlu vvayauem jjigvoz’r ziyp issezofsjl tuve uw-cketa ufq uxec kjorEt zo tibu akuzirgp awoufg. Mopmu vufz, pb kazkvasd, eqvaxaxew iqjadeobim kavesj ji wa ujx dugt. Gib kupx? Scuya ici zoj5(t) zobirc ap japocfiin ecm up iewd qubah w afivesln ipo ebaf. Ssuk logud qre himag I(k rot m) ip hzizu kijlmuqesv. Tazre fonh ix upi ef qki catnyafb veflobc ikwugayqxc. Uw’j nekesuwovj jenqjo wu atzunhvebb, acx lekmoc oq e qgaod ermziwefteel gi lub wotohe-afx-miktuan uzleqabqfd raxs. Zaxza lorm oj A(c run v) uvc pguq iwrlapaysiruom zesiuyoh E(m jad s) ez lkexu. Ag doe iye kieckw sxulob naxd xaix muizmiepavj, fee nan qaneyo kji huguxf xelaelij qi E(b) st dakfayxihg mbu jarokc fkig uy ten ostobibn qeebw inub.
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.