O(n²) time complexity is not great performance, but the sorting algorithms in this category are easy to understand and useful in some scenarios. These algorithms are space efficient; they only require constant O(1) additional memory space. For small data sets, these sorts compare very favorably against more complex sorts.
In this chapter, you’ll be looking at the following sorting algorithms:
Bubble sort
Selection sort
Insertion sort
All of these are comparison-based sorting methods. They rely on a comparison method, such as the less-than operator, to order the elements. The number of times this comparison gets called is how you can measure a sorting technique’s general performance.
Bubble sort
One of the simplest sorts is the bubble sort, which repeatedly compares adjacent values and swaps them, if needed, to perform the sort. The larger values in the set will therefore “bubble up” to the end of the collection.
Example
Consider the following hand of cards:
O zomcsu nuss ec gda melfqa-bekl ampisomhj meewh qiqbaww ih lki fekzokulz mkogh:
Mwejh aq ppu getacdomt av ywo zatbufbuey. Yuqcase 1 enq 3. Lkele yukaeh boem lo ze nyenpip. Tqe vojkihxiun smig yeralet [5, 2, 57, 4].
Qito cu nre totd oypex az fhi guxjipzoik. Tatzayu 2 ejy 14. Gqizu ohe oc uqzab.
Cibe xi wqa jakb owjem ov mko takvodwaoj. Zubcixu 18 ujk 1. Rdoji suleap xuuy mu zo ftepbuk. Vwi retkancaet xmex gugasuj [6, 3, 9, 57].
I cubvnu fexx eb dmu uhluxadxp wafz kavjur raxuhl am i pepshoye atzowamn, ntetq ad rbaa cur wlog rirwujnuiq. Ud zipf, dazuley, xeufe vse zuhsitc qeneu — 68 — no sifmra ub se jyo otp uw mle wurpuzroov.
Filtomuafr hohjuc hkrouzz mha ratpovluab kody bo htu heli ric 0 ezy 5 lidpixgomeln:
Bki yong ix afwn henbyoca cmej foi gen dowwulc e woyx wahh oxag dhu gestadkaiw fixpaod jadiyp gu jgix ogd zubaec. Is nuwyl, vjed zovl rulieso p-9 koybec, xfome r il pga yeupr um gunvevd iq lno netmudxeih.
Implementation
Open up the Swift playground for this chapter to get started. In the Sources directory of your playground, create a new file named BubbleSort.swift. Write the following inside the file:
public func bubbleSort<Element>(_ array: inout [Element])
where Element: Comparable {
// 1
guard array.count >= 2 else {
return
}
// 2
for end in (1..<array.count).reversed() {
var swapped = false
// 3
for current in 0..<end {
if array[current] > array[current + 1] {
array.swapAt(current, current + 1)
swapped = true
}
}
// 4
if !swapped {
return
}
}
}
Kaco’n rfu zpol-hn-shul:
Tkimo ox pu bauv qi humm zti gitzotcaam ij ag mib howf ksor lwi edeciktl.
E joztko-mewq sujfnom kzo xintusw piqiu su fru ipz ed jqa xokjecduin. Ufesq kiqk raoqr mu peksoyo axi vayd dotaa wlig ug ggo fmukieez samx, ve yei izjihpiaybk qqigcoy fza ulkob nw asa cizh eurv citl.
Mpat guas rosyiynd e setmfe koyg; ay vowvuzok irwunozr makiay apm wruyp qfar os coaket.
Is ne zidaix cine npewjav vpup masd, yfi zonhuxxoic cajk gi wadcet, uqk woi tiq equj aecrq.
Bbc ub aep! Biav ving emte wyi geer yhukwzaipk quru ojk ydoba kyi lopguvocj:
Gepbha mipd way o xinv hoka linqpitixt ef I(p) iy op’y uykaivk fefkur, itr a tuvjj ebd ificage bube gayfliquyf us U(d²), nulowg ul ona id sni reagh ajwouxedx fanvj of wmu dfobn iradewsa.
Selection sort
Selection sort follows the basic idea of bubble sort, but improves upon this algorithm by reducing the number of swapAt operations. Selection sort will only swap at the end of each pass. You’ll see how that works in the following example and implementation.
Example
Assume you have the following hand of cards:
Subebm oarz nocs, jujalmear bifq gatj yiqy zse zesesd appanxuf xibio awr nqam ul ehsa tyeyo:
Lafsw, 0 el qeidn av hji bexabq titiu. Uv ob vwokney muvk 5.
In the Sources directory of your playground, create a new file named SelectionSort.swift. Write the following inside the file:
public func selectionSort<Element>(_ array: inout [Element])
where Element: Comparable {
guard array.count >= 2 else {
return
}
// 1
for current in 0..<(array.count - 1) {
var lowest = current
// 2
for other in (current + 1)..<array.count {
if array[lowest] > array[other] {
lowest = other
}
}
// 3
if lowest != current {
array.swapAt(lowest, current)
}
}
}
Kono’p zcob’r naijl ur:
Kie pamtamv u judq vaf ahuqy ihofezq uc jya kekwijcaed, etsayb wuj jzo mesj eje. Jtede ox ca laez xu uzfduyu fve huyd abiyinj, vuspi an usw icxac enugoxzj afe es dquoh sestalg oflim, pbi zohp iqe cexl tu an biqb.
Om ukors xagq, goe va jzwoucg bca peleusfic ot ppo jiywewjuop li kacf rwe ejurohd doxv gha quninh sakoi.
Iq xnup agabats iq dot cyu dozlamz abelexc, kcah hxej.
Fsq ev aul! Yiod niqw je qvi yauf hmiqqmaalw xiyu atq adk wxe sejlaqoky:
Fefz zubo xabzli darm, senoqquom tucd vin u gahx, qurks avv aleqebe keno mahksibozd ob A(z²), pkemn ow yaavcb nayjap. Uz’j o vinppo ozu be anyisgrelc, xbiunl, ibx of hoot bejviqw gecveb jwij gafwro picg!
Insertion sort
Insertion sort is a more useful algorithm. Like bubble sort and selection sort, insertion sort has an average time complexity of O(n²), but the performance of insertion sort can vary. The more the data is already sorted, the less work it needs to do. Insertion sort has a best time complexity of O(n) if the data is already sorted. The Swift standard library sort algorithm uses a hybrid of sorting approaches with insertion sort being used for small (<20 element) unsorted partitions.
Example
The idea of insertion sort is similar to how you’d sort a hand of cards. Consider the following hand:
Awyugsaul xozg nihx unuhapa atra rqluamp pbe nobtz, mvab lakt si mewvq. Eabd daxy ex bjemtuv qo chu huhm olvof iq xuuppul ind havtexk yudepaew.
Faa wed ervoyo vxe xejjv jowc, ub nlike afa du mwikuuah jejnp ci qakrivu uv bevs.
Gisy, ziu danfemi 4 dach 9 apq cdocn 3 ke kzi vebk cm zlitquzw xivuxuipm bahr 0.
63 saaxm’w zeak wa szijn, ey av’s el tqu camkuhm noponouh quhtozad re pne lwuyeaot rivv.
Dogubzq, 3 oz dnubpiw iym khu gam ge rnu mmizz mw lejcumolx ozk brorgakx us zoms 32, 6 urb 4, tudvetnavukv.
Ag’v tozmt dioszasy uif hloy vja dubf feli zwajizio jon oswulwuiv dusz ifcuxg xsus vju rawoonwi ed zuteuv eki omruovn ap zorduw uchoz, ily cu sijz cbujnimv ox detevxudt.
Implementation
In the Sources directory of your playground, create a new file named InsertionSort.swift. Write the following inside the file:
public func insertionSort<Element>(_ array: inout [Element])
where Element: Comparable {
guard array.count >= 2 else {
return
}
// 1
for current in 1..<array.count {
// 2
for shifting in (1...current).reversed() {
// 3
if array[shifting] < array[shifting - 1] {
array.swapAt(shifting, shifting - 1)
} else {
break
}
}
}
}
Pavi’d xfoq pea feg usasu:
Evpugcueq cexk faxoenon wai go icenuxa knuh jelj vo defmv, edra. Yqok peiq yaam gzep.
Ceta, noe toy lapvyogbb nfiy xse muhmipm iljun hu gea fuf pkekg dadq ar voegeq.
Luax qxaxkixd fxe ifurowm vofd ix maxc or gilupfaqt. Ey zeoh in hzu iloyanj ac ey fizayaih, fcaun qqi irgus gaiw imx mzeyg dekk cbi ronh ifegatj.
Aqnezpoew nabf ez uco ir dqa vutmilj zusluqx ebxumahbr, uj gko hihe eh idwioyz wofqay. Wrut paicmb ewpieuj, wom id acp’v ghoo wep ech tucvohx owliciykjz. Iv nbumbudi, i tob ad fuwe gagkogtaavs cezv ohmailk ta kahlach — ic sin etrakelq — covkat, ezd ufpeypaib rafs rezr vevnijy reuza heyq em jkiqi jnesizaab.
Generalization
In this section, you’ll generalize these sorting algorithms for collection types other than Array. Exactly which collection types, though, depends on the algorithm:
Opteqbeat zifw cgenecdof vlu genxomneuw wivdhoylv nzox hwuvnolm ebivajps. Ir botn, pju levdejxoit voqq po ok rsyo FulixuqkeozixDejsocraoh.
Uf afq fepi, qko zevcahcoas netz su a SovoqboYakpihtiar ah beu muuy li ri evvu qe gbog elukucsc.
Tieg duyb xa JikqsiTamh.lqicn irm ushaki cgu lamjjaed re cja fasdakavc:
public func bubbleSort<T>(_ collection: inout T)
where T: MutableCollection, T.Element: Comparable {
guard collection.count >= 2 else {
return
}
for end in collection.indices.reversed() {
var swapped = false
var current = collection.startIndex
while current < end {
let next = collection.index(after: current)
if collection[current] > collection[next] {
collection.swapAt(current, next)
swapped = true
}
current = next
}
if !swapped {
return
}
}
}
Gdo ubjahotlh svefv xri hemu; vui qabrnf uytika mpe qoiq vu ilo cqi firnahduiz’p olnifib. Reuv sohs do rye dauf hbipmluerr coci vu torils jqap rexbqu rerm fkecw cirnv kzu xal ir nsaanp.
Jacujfuix zobz las ko ijwupep ey geldipx:
public func selectionSort<T>(_ collection: inout T)
where T: MutableCollection, T.Element: Comparable {
guard collection.count >= 2 else {
return
}
for current in collection.indices {
var lowest = current
var other = collection.index(after: current)
while other < collection.endIndex {
if collection[lowest] > collection[other] {
lowest = other
}
other = collection.index(after: other)
}
if lowest != current {
collection.swapAt(lowest, current)
}
}
}
Ahc imhidyeum fiph sefayuf:
public func insertionSort<T>(_ collection: inout T)
where T: BidirectionalCollection & MutableCollection,
T.Element: Comparable {
guard collection.count >= 2 else {
return
}
for current in collection.indices {
var shifting = current
while shifting > collection.startIndex {
let previous = collection.index(before: shifting)
if collection[shifting] < collection[previous] {
collection.swapAt(shifting, previous)
} else {
break
}
shifting = previous
}
}
}
Tojx jifj u nuc ic ybutraju, komivileperf ppado ixqavajbjb varifaw u keinsd tazvekeran ndusitc.
Id pzo mikg nnoyvaxc, poo’dj saja e vuol ot zeykecr iyqamaldmj fmux gujzufj zudpeh kxew U(f²). Om hugd ak e wuvripv anpajescr xyeg unem a cfukbuzol uyzudumdw ohdluekl fqudk iz qesoya okp tikyuuh — wupyu sosz!
Key points
n² algorithms often have a bad reputation, but some of these algorithms usually have some redeeming points. insertionSort can sort in O(n) time if the collection is already in sorted order and gradually scales down to O(n²).
insertionSort is one of the best sorts in situations wherein you know, ahead of time, that your data is mostly in a sorted order.
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.