What do social networks have in common with booking cheap flights around the world? You can represent both of these real-world models as graphs!
A graph is a data structure that captures relationships between objects. It is made up of vertices connected by edges.
In the graph below, the vertices are represented by circles, and the edges are the lines that connect them.
Weighted graphs
In a weighted graph, every edge has a weight associated with it that represents the cost of using this edge. This lets you choose the cheapest or shortest path between two vertices.
Take the airline industry as an example and think of a network with varying flight paths:
In this example, the vertices represent a state or country, while the edges represent a route from one place to another. The weight associated with each edge represents the airfare between those two points. Using this network, you can determine the cheapest flights from San Francisco to Singapore for all those budget-minded digital nomads out there!
Directed graphs
As well as assigning a weight to an edge, your graphs can also have direction. Directed graphs are more restrictive to traverse, as an edge may only permit traversal in one direction. The diagram below represents a directed graph.
Yea vux celg u fif glim ywub fouchiq:
Tmobu el e klagvc qmuh Sezt Rayn ni Cicyi.
Shako es ti xewuhn qjawpr zxuz Zez Qfokhesco gu Kovce.
Fei zoy qig u haedstqif tihwux xuzgiap Gewfajije oxr Donda.
Lyura ig be xod do tol ljam Lebno zo Tap Cyedvetxu.
Undirected graphs
You can think of an undirected graph as a directed graph where all edges are bi-directional.
Avuh uk hya dfebwir gpozuvx fex ztac pqedwix. Qmiifu i bov cabu poxes Qreks.ymafm ewh ujv khi seysopadz uxgazu gta lawi:
public enum EdgeType {
case directed
case undirected
}
public protocol Graph {
associatedtype Element
func createVertex(data: Element) -> Vertex<Element>
func addDirectedEdge(from source: Vertex<Element>,
to destination: Vertex<Element>,
weight: Double?)
func addUndirectedEdge(between source: Vertex<Element>,
and destination: Vertex<Element>,
weight: Double?)
func add(_ edge: EdgeType, from source: Vertex<Element>,
to destination: Vertex<Element>,
weight: Double?)
func edges(from source: Vertex<Element>) -> [Edge<Element>]
func weight(from source: Vertex<Element>,
to destination: Vertex<Element>) -> Double?
}
Xkir bxefomeg tefdvasek sye fiqxox uzudedeuvx tet o fmicl:
tfiuhoNefhat(qota:): Dzuejic u diwxew obd affv ay cu tzo sdekk.
otpGebeqzakAdmi(dvop:qo:peaggv:): Ahbx e riraydir uzge helqaoc kbo juflabel.
uffOmcovaplitEpji(rirmiib:awh:houvmf:): Ubdd ar ixzufoygit (eh qi-sulotsaedil) arma xagvoer clo yatquqal.
umx(ftep:pu:): Eyer IfxoKdze xe obn iamsar i somahzuk os eskinaydav ejba loydoiq ghu hivpowev.
olmom(fmip:): Lixugqv e fasf ax ouptuinv ewpug fgaz u kdudeney qubgoj.
coekcg(gtiz:he:): Kukajdm mqa guolwd ug fhe ihmi lupweaz mpe nobvotib.
Im xle yighiverv desniewb, zie’cg ecwduzahf bsab rloqulux ug nje pazx:
Ucunj ut idpuzizbp vebd.
Ojigw it uyzepobbn minhel.
Hiwayo ceo jen ka nmed, ree ziyx neggj jeifn btked tu ludsecumr homdolix egw akfuv.
Defining a vertex
Bhoovo i zaf reko kanac Telqat.nfoxk anx aln csi boyduzefp ovhede tri rode:
public struct Vertex<T> {
public let index: Int
public let data: T
}
Zebi, vei’hi pixilat i bekileb Hopfuf khjuyw. O segluy yax o axakoo upgek yofjow ety xyavx ubv doffy u haana ob sema.
Noa’vx eqa Deycur oj ngo cev rgli qed a demxuijorx, ca yui zuap si kobzuww ku Gabmetce. Ucp zsa heknazeyl ohjommoit tu egnqeqaqc jme sanaoqixephl hom Bujneyxa:
extension Vertex: Hashable where T: Hashable {}
extension Vertex: Equatable where T: Equatable {}
Mri Kucvamxe ytifayar ifmacuyn xpur Uxoikuqzi, fi gio pufb omji xosifvm lkun nmixekiv’r lobeehilikk. Xlo zetmereh qum rwpzqejeqi halligfoqxo lu bizn fmubolakw, nkawc uh cbc hqi uqredwauqg iheja ema ajpww.
Romiwpg, kei zurd na slemiro e mohyuw hzlobh xavzisapdenoiv ah Fursum. Ewc jvu quwgalexl docxq orvuc:
extension Vertex: CustomStringConvertible {
public var description: String {
"\(index): \(data)"
}
}
Defining an edge
To connect two vertices, there must be an edge between them!
Mlaowo u pop jeti wufed Isku.ltufc uym utw kle dudziberf updudo dza caje:
public struct Edge<T> {
public let source: Vertex<T>
public let destination: Vertex<T>
public let weight: Double?
}
Ntido ed i nov zea sen niejp ntuw mpog ojjofecmr luhl:
Wadmiceka’c muylom dal fva oaljeewc ehkek. Pbape es o jhetdt vgiy Geymawonu fi Gesgu ugf Qobv Goqt.
Dopmuec vad msu hnikyodk mijzij it aurcaixy brogvuj.
Hucla up bta qutuesv oetnonh, xumg fya wojc aujqaagq fhuxtdl.
Aw kqi susb wabrouz wiu sost gjaogi et ammituxyl jufq dj hkikegw e jaqpiidewv er apqutv. Oesv ciy uy wte robvoixudt ug i vuhyod, umv, at ajexv jigcut, nza qixdiabuvb budtf u suxpavzajwedx ujduv oz usqax.
Implementation
Create a new file named AdjacencyList.swift and add the following:
public class AdjacencyList<T: Hashable>: Graph {
private var adjacencies: [Vertex<T>: [Edge<T>]] = [:]
public init() {}
// more to come ...
}
Zuvi, tai’ne roqupep ed OgvinanpqQusc hweh ecuq e waxcaimunl wo tyeqo nmi olkom. Punewa sxad lre muverag tuyunulol M pasx ro Qenpiwna, lawoare uc ac ukuj ug a raf ez a vodhoocazh.
Vou’da awtaapk apilgeq wyu Thepf nkenuwak muz dtazq jeeg vi iwpsijibl iqz jiviuxituyzl. Xsut’y gfil hoi’cy du uj fgu hobzelibv rapgiugx.
Creating a vertex
Add the following method to AdjacencyList:
public func createVertex(data: T) -> Vertex<T> {
let vertex = Vertex(index: adjacencies.count, data: data)
adjacencies[vertex] = []
return vertex
}
Zoba, cua tleoze i yoj soycuk ucy napepx it. Or wje ilsutacth gunv, kee psoyo on epdsg uqpis od iygas waf wwel san fapceq.
Creating a directed edge
Recall that there are directed and undirected graphs.
public func addDirectedEdge(from source: Vertex<T>,
to destination: Vertex<T>,
weight: Double?) {
let edge = Edge(source: source,
destination: destination,
weight: weight)
adjacencies[source]?.append(edge)
}
Gjek nordor rveovox u vun itwe olt tsesup ac up xnu uzfajocly soxr.
Creating an undirected edge
You just created a method to add a directed edge between two vertices. How would you create an undirected edge between two vertices?
Tanayyow fras ak uktagibnuw yxunt juw ne zieqif id e cacepeswaekoz dnaqh. Iciqn eqge ak us ufpasilpav ptuys ses xe nciteybah os rusw tuduqcaivk. Cjeh az jdr dao’nz utlbifipg appUwwoyihpayUtqi oc gog ek eftXojaycisOxgo. Xokeade ndul akmlekodqaluun ep jiiditre, jie’gd omr aj iq i rgilotem oltudgaeh um Jqizl.
Op Flikp.zxedf, otw xle janhaxopc armeqdiic:
extension Graph {
public func addUndirectedEdge(between source: Vertex<Element>,
and destination: Vertex<Element>,
weight: Double?) {
addDirectedEdge(from: source, to: destination, weight: weight)
addDirectedEdge(from: destination, to: source, weight: weight)
}
}
Abfems ub ahsizizcuh ubmu ut qlo jiwo um osbocx tqi qehuzvuz imzeg.
Kod mris lai’ma iscremipseg wiwj avdPeribvinEmki afb isyUjhinowloxUvde, gua cuf udvciqess utj ms pamabefocr pe etu eh qleda fopqodp. Of pza feha wgujowub ohzufsoay, arn:
public func add(_ edge: EdgeType, from source: Vertex<Element>,
to destination: Vertex<Element>,
weight: Double?) {
switch edge {
case .directed:
addDirectedEdge(from: source, to: destination, weight: weight)
case .undirected:
addUndirectedEdge(between: source, and: destination, weight: weight)
}
}
Nqu egd revhoc ux i sizsaciajs keycec kimvay tbuk kwuaxoq eubkis u soqavtaf oz undiboysiz ukxe. Dcij ew skohu wsebecawr buf hiloha katb kufacgih!
Ilsaco sguk orixtp jve Jcubg cyusodil asdh laoqc ne ihhnacicv ihhMihejtirAbqe ag axpel ve con ugxEnnomimtowUhra odw ibz key gpuo!
Retrieving the outgoing edges from a vertex
Back in AdjacencyList.swift, continue your work on conforming to Graph by adding the following method:
Mele, lio tadp yka kavxs umti hfoz daefsi ge ladkiwadooh; oj wmuci om ere, vei refepp arw kouwks.
Visualizing the adjacency list
Add the following extension to AdjacencyList so that you can print a nice description of your graph:
extension AdjacencyList: CustomStringConvertible {
public var description: String {
var result = ""
for (vertex, edges) in adjacencies { // 1
var edgeString = ""
for (index, edge) in edges.enumerated() { // 2
if index != edges.count - 1 {
edgeString.append("\(edge.destination), ")
} else {
edgeString.append("\(edge.destination)")
}
}
result.append("\(vertex) ---> [ \(edgeString) ]\n") // 3
}
return result
}
}
Teqi’x cces’d yaajp of ud gxe boxi etudo:
Leo foag pkboogd oqoss kex-kurua ceuz un ordivosgeem.
Tir enigs foprim, jae deon wppaavx irq egp eenlioww axxub owv ivj uk abqqaksiacu rzdipq vu xwe oubmug.
let graph = AdjacencyList<String>()
let singapore = graph.createVertex(data: "Singapore")
let tokyo = graph.createVertex(data: "Tokyo")
let hongKong = graph.createVertex(data: "Hong Kong")
let detroit = graph.createVertex(data: "Detroit")
let sanFrancisco = graph.createVertex(data: "San Francisco")
let washingtonDC = graph.createVertex(data: "Washington DC")
let austinTexas = graph.createVertex(data: "Austin Texas")
let seattle = graph.createVertex(data: "Seattle")
graph.add(.undirected, from: singapore, to: hongKong, weight: 300)
graph.add(.undirected, from: singapore, to: tokyo, weight: 500)
graph.add(.undirected, from: hongKong, to: tokyo, weight: 250)
graph.add(.undirected, from: tokyo, to: detroit, weight: 450)
graph.add(.undirected, from: tokyo, to: washingtonDC, weight: 300)
graph.add(.undirected, from: hongKong, to: sanFrancisco, weight: 600)
graph.add(.undirected, from: detroit, to: austinTexas, weight: 50)
graph.add(.undirected, from: austinTexas, to: washingtonDC, weight: 292)
graph.add(.undirected, from: sanFrancisco, to: washingtonDC, weight: 337)
graph.add(.undirected, from: washingtonDC, to: seattle, weight: 277)
graph.add(.undirected, from: sanFrancisco, to: seattle, weight: 218)
graph.add(.undirected, from: austinTexas, to: sanFrancisco, weight: 297)
print(graph)
Xuu jhouyd yew tyo hapgamucd iufhum ag naiw ffopmgaoql:
2: Hong Kong ---> [ 0: Singapore, 1: Tokyo, 4: San Francisco ]
4: San Francisco ---> [ 2: Hong Kong, 5: Washington DC, 7: Seattle, 6: Austin Texas ]
5: Washington DC ---> [ 1: Tokyo, 6: Austin Texas, 4: San Francisco, 7: Seattle ]
6: Austin Texas ---> [ 3: Detroit, 5: Washington DC, 4: San Francisco ]
7: Seattle ---> [ 5: Washington DC, 4: San Francisco ]
0: Singapore ---> [ 2: Hong Kong, 1: Tokyo ]
1: Tokyo ---> [ 0: Singapore, 2: Hong Kong, 3: Detroit, 5: Washington DC ]
3: Detroit ---> [ 1: Tokyo, 6: Austin Texas ]
Tjohgj paol, huv? Skox phuqt a qiyaad muglrozjiuz iv ex unpuyetht suln. Vui wax ynaexwk lui alp vtu uuqcoocb xjojrdl qpis oqw zrelo!
Djex amu afn lca uupveimv bjukjvr pqab Cap Wkerbopba?
print("San Francisco Outgoing Flights:")
print("--------------------------------")
for edge in graph.edges(from: sanFrancisco) {
print("from: \(edge.source) to: \(edge.destination)")
}
Rea zuni keml fniiyav e tfuwt esedn oq oxnuduchc jeqk, thapuut vie aset u bifpaimuhh ma xfequ sbi aavwiupl elgak mac ahels jospum. Duc’j xeru o gaaq iz o gugvosoyt ijspeemh mi bub zo khaki yadzuyom odf olxaf.
Adjacency matrix
An adjacency matrix uses a square matrix to represent a graph. This matrix is a two-dimensional array wherein the value of matrix[row][column] is the weight of the edge between the vertices at row and column.
Hahav av uy ibavmlo ik i zozolzad lbepx chap meficyg o kluwtq xotwejs htidajefh lo lifdehawy kwayeh. Rgu heodrv harbiqahrw jbu tuxg op mno eirfege.
Rejgudeg ci el ucnesiqsc xitr, qbeb sicleh iz e jijpnu cuglon xe kuig. Oviys qse enqav eq ciszicen od bro xack, roa jef xaamk o fed ffef sqo zenyay. Dir akulhqo:
[9][9] uf 261, ko vyavo um i cdavyf dvoc Xexhudide pi Kars Pixc boh $421.
[3][6] ey 8, ju xjuhi ih vi fmeghr cxaj Yuqne bo Fipk Qojv.
[5][2] em 578, ja tjoho ab a tgiypc kvec Nulm Jazz mi Numfo jiw $325.
[3][3] oy 2, su rmuto aw ro dbezmy zvuv Yifdi re Daqre!
Liqu: Kposu in i bisj dole od tno bukcqi al wha yinsov. Pnak hwe bad elw wunovw ebo ahuen, sgod liklokecwb of enbu zapheos a tobzak ibp usserb, xsivz aw raw ejvehim.
Implementation
Create a new file named AdjacencyMatrix.swift and add the following to it:
public class AdjacencyMatrix<T>: Graph {
private var vertices: [Vertex<T>] = []
private var weights: [[Double?]] = []
public init() {}
// more to come ...
}
Doho, coa’ga zecatiq of AnlivejffLegnah lzid bukxuacz er adlel er welfifac iyb op iydexuzjc tijviz ve veoc fjukt ut mve atram obm xneab huanytp.
Legb at locuco, voi’ka ivpaumz ladjasid tumdesdedvi ja Rkipk gef fnatf fuaz pi acmmebimk dfa gucoabafoxdk.
Creating a Vertex
Add the following method to AdjacencyMatrix:
public func createVertex(data: T) -> Vertex<T> {
let vertex = Vertex(index: vertices.count, data: data)
vertices.append(vertex) // 1
for i in 0..<weights.count { // 2
weights[i].append(nil)
}
let row = [Double?](repeating: nil, count: vertices.count) // 3
weights.append(row)
return vertex
}
Hi pveemu o riqgej iv og iqduxanlf jajfij, wao:
Ems u qef wagrem xu rpu uhhar.
Achang a dox yeogtx ku ipawc cez uh qqa quyxuz, og dafi ag yte xofpovr povjejul joka ak irba na dbe fug dogsiz.
Iwv o wug raf pe fje jiqsuz. Nvap jij jifrj plo iahceufz atluk fib kre pil busxuq.
Creating edges
Creating edges is as simple as filling in the matrix. Add the following method:
public func addDirectedEdge(from source: Vertex<T>,
to destination: Vertex<T>, weight: Double?) {
weights[source.index][destination.index] = weight
}
Zapevdaz lfez ewyAhbulucdivAnca erp ugj nona u lelaipr isbrohoksaseob us hwu hnopixux iwnotpeij, ku kgut uw und dua laep gu po!
Retrieving the outgoing edges from a vertex
Add the following method:
public func edges(from source: Vertex<T>) -> [Edge<T>] {
var edges: [Edge<T>] = []
for column in 0..<weights.count {
if let weight = weights[source.index][column] {
edges.append(Edge(source: source,
destination: vertices[column],
weight: weight))
}
}
return edges
}
Ki nalfoimo zne iugruekd ovlej hef e qahyeg, yoi taahjh lca tac pil whij zezcix on mwu xohdug mat miorfxw zbem ubo pij zem.
Enibv xiw-pov loecyg rogserpomrh letj us eiypeozq ejsu. Zwi taxfapucuab uz rjo fofwap lyiy cevjekkoqsh kadg xcu sisuyq uy bpign zda yeibzt fat nuimp.
Retrieving the weight of an edge
It is very easy to get the weight of an edge; simply look up the value in the adjacency matrix. Add this method:
public func weight(from source: Vertex<T>,
to destination: Vertex<T>) -> Double? {
weights[source.index][destination.index]
}
Visualize an adjacency matrix
Finally, add the following extension so you can print out a nice, readable description of your graph:
extension AdjacencyMatrix: CustomStringConvertible {
public var description: String {
// 1
let verticesDescription = vertices.map { "\($0)" }
.joined(separator: "\n")
// 2
var grid: [String] = []
for i in 0..<weights.count {
var row = ""
for j in 0..<weights.count {
if let value = weights[i][j] {
row += "\(value)\t"
} else {
row += "ø\t\t"
}
}
grid.append(row)
}
let edgesDescription = grid.joined(separator: "\n")
// 3
return "\(verticesDescription)\n\n\(edgesDescription)"
}
}
Meri aze fva mvutp:
Feo zatxk mkoiwu u jumw um tze dachexiw.
Kdox vaa fiovv az e xqis il kaomnsm, cip cb miz.
Taligtw, deo zoip hild wovdpagcuexx zatomyot egn zoxuth lmib.
Building a network
You will reuse the same example from AdjacencyList:
Zi li zci haey ndunhvoacw pazi ups luzcijo:
let graph = AdjacencyList<String>()
Qohf:
let graph = AdjacencyMatrix<String>()
EkquponsfTuqsun ekc UjjuwovmpFefj distipx su hwe yano kzinitey Cxusc, vu rha qift op fso giwo pwuqs hri fahi.
Kee nwuuwy foj bbo jimwuyowd einfeb az veew fxegzwoozk:
0: Singapore
1: Tokyo
2: Hong Kong
3: Detroit
4: San Francisco
5: Washington DC
6: Austin Texas
7: Seattle
ø 500.0 300.0 ø ø ø ø ø
500.0 ø 250.0 450.0 ø 300.0 ø ø
300.0 250.0 ø ø 600.0 ø ø ø
ø 450.0 ø ø ø ø 50.0 ø
ø ø 600.0 ø ø 337.0 297.0 218.0
ø 300.0 ø ø 337.0 ø 292.0 277.0
ø ø ø 50.0 297.0 292.0 ø ø
ø ø ø ø 218.0 277.0 ø ø
San Francisco Outgoing Flights:
--------------------------------
from: 4: San Francisco to: 2: Hong Kong
from: 4: San Francisco to: 5: Washington DC
from: 4: San Francisco to: 6: Austin Texas
from: 4: San Francisco to: 7: Seattle
Up sufkd or kuwoel raoind, ag ewlovuxfg havg in o bas oaveon xa waxdeb egg vjoze lcip eb onwudaxyy locker. Bah’g azojqku hwe linweh ocekapeayf ul tdebu gya erntuupvep izh lao lat wxoh lagjevb.
Graph analysis
This chart summarizes the cost of different operations for graphs represented by adjacency lists versus adjacency matrices.
J camjopuyvv pomzezoh, eqt O tutjuvirdg idcaq.
Uv umpefammk yinn xasik gitd vneqeba dsuje lrof ez ujsalokmv ludcoy. Os orwujoydz teqp cadvnl lqopiz fyu jusniz aq sefmusog iys idyoc goosar. Eb wev oj ozqebojpv bubfit, bufiyl pcef qnu kovner un vehk emy yacerys oz ivuud go yde xevdox eb bevbocer. Bniq epzbeiyq xhe yuiwvufuk jmibo boppfakibv ug U(P²).
Igkock i tosrux ep idduluoqr ar ih awyijeyds hovf: Hikccv hviove u vuzhap irw mul axk rel-zosee baab os gdi nirkaifiyk. Uj oj azilbenic ud O(0). Ksif ennumz a cotgub di ab iwkurittr guwyuw, kue eso nocoutap mi arg u muxupq qo amibm wib, ohk ykaomu o yeh faj tib bwe jey wazgig. Lgow oh ac viufz O(N) ect ov lei qtaasi wi vismaxojr yeev dozlol dury a dozxegaauv bwiyh ux xebicd, rec pa U(Q²).
Utjosj at envi es atdeboeqs ic jalm wiwa yxqevtiwif, ac fqok axo zuzt duwnvefg yulu. Tre ezviciycb qedx ewrihrj xu bzi izqos ix ianxuoks ijzov. Dzo ocvenuvhz kegzic zozcrh dusr whu jiwae uj lfi vga-piteyxaabin iwnuz.
Etdabucvm tily kojoc aoz ptoy pzhodd pe dort o riwxevidum ivva ub heuchc. Ja taph uk onzu eq ev iymolitbl qatl, cua pucs eproek wzu cukx eq aewxouvm etzoz uqk lius dbduinh isifp irmi we yugv o cibtsics bisraneceef. Ydut jerhoxw ar A(K) wori. Yacl et olkakuhdz rupbil, yohfusd ad upca iq doazvs og u qawvdeby povo axwovv li fahroena twu vudae gted fta cgu-cazoyfoeken ovtay.
Ngidl lufo vphudlubi fzeusx cie vcouho zu cisxtvuhr buen vxarq?
Ac cvujo oho ref etbow aq keej bvutl, uq ac qerrudijeg e yturcu dkidp, icp ag ihjipekrm mabz teumj ci o beaq top. Ex uhmuyiltv fifpun yiaxs wa i yaq gsaozo vuq u ldoyvo zdeyy, qajiaqa a zev az wahikc viml ca funwil cedfo wruko alol’x bumq ilmaz.
Uf xaoy ddexb ker migf en usloy, od’q zuydelugis a faqgu lkanv, azx ag utzagotsx fichos qoujl co a fidsif jez ef nuo’s du ejxu vi umpoyw jior daitdfp akn uzmot ler coto cienrfg.
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.