您的位置:首页 > 编程语言 > Go语言

Graph Data Structures for Beginners

2018-08-10 09:56 337 查看


Inthispost,wearegoingtoexplorenon-lineardatastructureslikegraphs.Wearegoingtocoverthecentralconceptsandtypicalapplications.

Youareprobablyusingprogramsthatusegraphs(andtrees).Let’ssayforinstancethatyouwanttoknowtheshortestpathbetweenyourworkplaceandhomeyoucanusegraphalgorithmstogettheanswer!Wearegoingtoexplorethisandotherfunchallenges.

Inthepreviouspost,weexplorelineardatastructureslikearrays,linkedlists,sets,stacksandsoon.Thispostbuildsontopofwhatwelearned.

Thispostispartofatutorialseries:

LearningDataStructuresandAlgorithms(DSA)forBeginners

Introtoalgorithm’stimecomplexityandBigOnotation

Eighttimecomplexitiesthateveryprogrammershouldknow

DataStructuresforBeginners:Arrays,HashMaps,andLists

GraphDataStructuresforBeginnersyouarehere

TreesDataStructuresforBeginners

Self-balancedBinarySearchTrees

AppendixI:AnalysisofRecursiveAlgorithms

Hereisthesummaryoftheoperationsthatwearegoingtocoveronthispost:

AdjacencyListAdjacencyMatrix
SpaceO(|V|+|E|)O(|V|2)
addVertexO(1)O(|V|2)
removeVertexO(|V|+|E|)O(|V|2)
addEdgeO(1)O(1)
removeEdge(usingArray)O(|E|)O(1)
removeEdge(usingHashSet)O(1)O(1)
getAdjacentsO(|E|)O(|V|)
isAdjacent(usingArray)O(|E|)O(1)
isAdjacent(usingHashSet)O(1)O(1)

GraphsBasics

Agraphisadatastructurewhereanodecanhavezeroormoreadjacentelements.

Theconnectionbetweentwonodesiscallededge.Nodescanalsobecalledvertices.



Thedegreeisthenumberofedgesconnectedtoavertex.E.g.,thepurplevertexhasadegreeof3whiletheblueonehasadegreeof1.

Iftheedgesarebi-directional,thenwehaveaundirectedgraph.But,iftheedgeshaveadirection,thenwehaveadirectedgraphordi-graphforshort.Youcanthinkofitasaone-waystreet(directed)ortwo-waystreet(undirected).



Vertexcanhaveedgesthatgotoitself(e.g.,bluenode),thisiscalledself-loop.

Agraphcanhavecycleswhichmeansthatifyoutraversethroughthenode,youcouldgettothesamenodemorethanonce.Thegraphwithoutcyclesiscalledacyclicgraph.



Also,acyclicundirectedgraphsarecalledtree.Wearegoingtocovertreesindepthinthenextpost.

Notallverticeshavetobeconnectedinthegraph.Youmighthaveisolatednodesorevenseparatedsubgraphs.Ifallnodesarehasaleastoneedge,thenwehaveaconnectedgraph.Whenallnodesareconnectedtoallothernodes,thenwehaveacompletegraph.



Foracompletegraph,eachnodehastohave#nodes-1edges.Inthepreviousexamplewehave7vertices,soeachnodehas6edges.

GraphApplications

Whenedgeshavevalues/costassignedtothem,wesaywehaveaweightedgraph.Iftheweightisabsent,wecanassumeit’s1.



Weightedgraphshavemanyapplicationsdependingonthedomainwhereyouneedtosolveaproblem.Tonameafew:

AirlineTraffic(imageabove)

Node/vertex=Airport

Edges=directflightsbetweentwoairports

Weight=milesbetweentwoairports

GPSNavigation

Node=roadinsersection

Edge=road

Weigth=timerequiredtogofromoneintersectiontoanother

Networksrouting

Node=server

Edge=datalink

Weight=connectionspeed

Ingeneral,graphshavemanyreal-worldapplicationslike:

Electroniccircuits

Flightreservations

Drivingdirections

Telcom:Celltowerfrequencyplanning

Socialnetworks.E.g.,Facebookusesagraphforsuggestingfriends

Recommendations:Amazon/Netflixusesgraphstomakesuggestionsproducts/movies

Graphshelptoplanlogisticsofdeliveringgoods



Wejustlearnedthebasicsofgraphsandsomeapplications.Let’slearnnowhowtorepresentgraphsincode.

Representinggraphs

Threaretwoprimarywaysofrepresentinggraph:

Adjacencylist

AdjacencyMatrix

Let’sexplainitwiththefollowingdirectedgraph(digraph)asanexample:



Weadigraphwith4nodes.Whenavertexhaslinktoitself(e.g.a)iscalledself-loop.

AdjacencyMatrix

Theadjacencymatrixisonewayofrepresentingagraphusingatwo-dimensionalarray(NxNmatrix).Intheintersectionofnodes,weadd1(orotherweight)iftheyareconnectedand0or-iftheyarenotconnected.

Usingthesameexampleasbefore,wecanbuildthefollowingadjacencymatrix:

AdjacencyMatrix

1
2
3
4
5
abcde
a11---
b--1--
c---1-
d-11--
Asyoucansee,thematrixlistallnodeshorizontallyandvertically.Ifthereafewconnectionswecalledsparsegraphiftherearemanyconnections(closetothemaxnumberoflinks)wecalleditdensegraph.Ifallpossibleconnectionsarereached,thenwehaveacompletegraph.

It’simportanttonoticethatforundirectedgraphstheadjacencymatrixwillalwaysbesymmetricalbythediagonal.However,that’snotalwaysthecaseonadigraph(likeourexample).

Whatisthetimecomplexityoffindingconnectionsoftwovertices?

QueryingiftwonodesareconnectedinanadjacencymatrixisO(1).

Whatisthespacecomplexity?

StoringagraphasanadjacencymatrixhasaspacecomplexityofO(n2),wherenisthenumberofvertices.Also,representedasO(|V|2)

Whatistheruntimetoaddavertex?

TheverticesarestoredasaVxVmatrix.So,everytimeavertexisadded,thematrixneedstobereconstructedtoaV+1xV+1.

AddingavertexonaadjacencymatrixisO(|V|2)

Whataboutgettingtheadjacentnodes?

SincethematrixhasaVxVmatrix,togetalltheadjacentnodestoagivenvertex,wewouldhavetogotothenoderowandgetallitsedgeswiththeothernodes.

Inourpreviousexample,let’ssaywewantalltheadjacentnodestob.Wehavetogetthefullrowwherebwithalltheothernodes.

1
2
abcde
b--1--
Wehavetovisitallnodesso,

GettingadjacentnodesonanadjacencymatrixisO(|V|)

ImaginethatyouneedtorepresentFacebooknetworkasagraph.Youwouldhavetocreateamatrixof2billionx2billion,wheremostofitwouldbeempty!Nobodywouldknoweverybodyelsejustafewthousandsatmost.

Ingeneral,wedealwithsparsegraphssothematrixwillwastealotofspace.That’swhyinmostimplementationwewoulduseanadjacencylistratherthanthematrix.

AdjacencyList

AdjacencyListisoneofthemostcommonwaystorepresentgraphs.Eachnodehasalistofallthenodesconnectedtoit.

GraphscanberepresentedasanadjacencylistusinganArray(orHashMap)containingthenodes.Eachofthisnodeentriesincludesalist(array,linkedlist,set,etc.)thatlistitsadjacentnodes.

Forinstanceinthegraphabovewehavethatahasanconnectiontobandalsoaself-looptoitself.Inturn,bhasaconnectiontocandsoon:

AdjacencyList

1
2
3
4
a->{ab}
b->{c}
c->{d}
d->{bc}
Asyoucanimagineifyouwanttoknowifanodeisconnectedtoanothernode,youwouldhavetogothroughthelist.

QueryingiftwonodesareconnectedinanadjacencylistisO(n),wherenisthenumberofvertices.AlsorepresentedasO(|V|)

Whataboutthespacecomplexity?

StoringagraphasanadjacencylisthasaspacecomplexityofO(n),wherenisthesumofverticesandedges.Also,representedasO(|V|+|E|)

AdjacencyListGraphHashMapImplementation

Theadjacencylististhemostcommonwayofrepresentinggraphs.Thereareseveralwaystoimplementtheadjacencylist:

OneofthemostsimpleisusingaHashMap.Thekeyisthevalueofthenode,andthevalueisanarrayofadjacency.

AdjacencyListasaHashmap

1
2
3
4
5
6
constgraph={
a:['a','b'],
b:['c'],
c:['d'],
d:['b','c']
}
Graphusuallyneedsthefollowingoperations:

Addandremovevertices

Addandremoveedges

Addingandremovingverticesinvolvesupdatingtheadjacencylist.

Let’ssaythatwewanttoremovethevertexb.Wecoulddodeletegraph['b'];,however,westillhavetoremovethereferencesontheadjacencylistondanda.

Everytimeweremoveanode,wewouldhavetoiteratethroughallthenodes’listO(|V|+|E|).Candobetter?Wewillanswerthatlater,firstlet’s*implementourlistinamoreobject-orientedwaysowecanswapimplementationseasily.

AdjacencyListGraphOOImplementation

Let’sstartwiththeNodeclassthatholdsthevertex’svalueanditsadjacentvertices.Wecanalsohavehelperfunctionsforaddingandremovingadjacentnodesfromthelist.

NodeCommentedCode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
classNode{
constructor(value){
this.value=value;
this.adjacents=[];//adjacencylist
}
addAdjacent(node){
this.adjacents.push(node);
}
removeAdjacent(node){
constindex=this.adjacents.indexOf(node);
if(index>-1){
this.adjacents.splice(index,1);
returnnode;
}
}
getAdjacents(){
returnthis.adjacents;
}
isAdjacent(node){
returnthis.adjacents.indexOf(node)>-1;
}
}
NoticethatadjacentruntimeisO(1),whileremoveadjacentisO(|E|).WhatifinsteadofanarrayuseaHashSet?ItcouldbeO(1).But,letfirstgetitworkingandlaterwecanmakeitfaster.

Makeitwork.Makeitright.Makeitfaster.

Ok,nowthatwehavetheNodeclass,let’sbuildtheGraphclassthatcanperformoperationssuchasadding/removingverticesandedges.

Graph.constructor

Graph.constructorFullCode

1
2
3
4
5
6
7
8
9
10
classGraph{
constructor(edgeDirection=Graph.DIRECTED){
this.nodes=newMap();
this.edgeDirection=edgeDirection;
}
//...
}
Graph.UNDIRECTED=Symbol('directedgraph');//one-wayedges
Graph.DIRECTED=Symbol('undirectedgraph');//two-waysedges
Thefirstthingthatweneedtoknowisifthegraphisdirectedorundirected.Thatmakesadifferencewhenweareaddingedges.

Graph.addEdge

Twoaddanedgeweneedtwonodes.Oneisthesource,andtheotheristhedestination.

Graph.addEdgeFullCode

1
2
3
4
5
6
7
8
9
10
11
12
addEdge(source,destination){
constsourceNode=this.addVertex(source);
constdestinationNode=this.addVertex(destination);
sourceNode.addAdjacent(destinationNode);
if(this.edgeDirection===Graph.UNDIRECTED){
destinationNode.addAdjacent(sourceNode);
}
return[sourceNode,destinationNode];
}
Weaddanedgefromthesourcevertextothedestination.Ifwehaveanundirectedgraph,thenwealsoaddfromtargetnodetosourcesinceit’sbidirectional.

Theruntimeofaddinganedgefromagraphadjacencylistis:O(1)

Ifwetrytoaddanedgeandthenodesdon’texist,weneedtocreatethemfirst.Let’sdothatnext!

Graph.addVertex

Thewaywecreateanodeisthatweaddittothethis.nodesMap.Themapstoreakey/valuepair,wherethekeyisthevertex’svaluewhilethemapvalueistheinstanceofthenodeclass.Takealookatline5-6:

Graph.addVertexFullCode

1
2
3
4
5
6
7
8
9
addVertex(value){
if(this.nodes.has(value)){
returnthis.nodes.get(value);
}else{
constvertex=newNode(value);
this.nodes.set(value,vertex);
returnvertex;
}
}
Ifthenodealreadyexistswedon’twanttooverwriteit.So,wefirstcheckifitalreadyexistsifnotthenwecreateit.

Theruntimeofaddingavertexfromagraphadjacencylistis:O(1)

Graph.removeVertex

Removinganodefromthegraph,it’salittlebitmoreinvolved.Wehavetocheckifthenodetobedeletedit’sinuseasanadjacentnode.

Graph.removeVertexFullCode

1
2
3
4
5
6
7
8
9
removeVertex(value){
constcurrent=this.nodes.get(value);
if(current){
for(constnodeofthis.nodes.values()){
node.removeAdjacent(current);
}
}
returnthis.nodes.delete(value);
}
Wehavetothrougheachvertexandtheneachadjacentnode(edges).

Theruntimeofremovingavertexfromagraphadjacencylistis:O(|V|+|E|)

Finally,let’sremoveimplementremovinganedge!

Graph.removeEdge

RemovinganedgeisprettystraightforwardandsimilartoaddEdge.

Graph.removeVertexFullCode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
removeEdge(source,destination){
constsourceNode=this.nodes.get(source);
constdestinationNode=this.nodes.get(destination);
if(sourceNode&&destinationNode){
sourceNode.removeAdjacent(destinationNode);
if(this.edgeDirection===Graph.UNDIRECTED){
destinationNode.removeAdjacent(sourceNode);
}
}
return[sourceNode,destinationNode];
}
ThemaindifferencebetweenaddEdgeandremoveEdgeisthat:

Iftheverticesdon’texist,wewon’tcreatethem.

WeuseNode.removeAdjacentinsteadofNode.addAdjacent.

SinceremoveAdjacenthastogothroughalltheadjacentverticeswehavethefollowingruntime:

TheruntimeofremovinganedgefromagraphadjacencylistisO(|E|)

Wearegoingtoexplorehowtosearchvaluesfromanode.

Breadth-frirstsearch(BFS)-Graphsearch

Breadth-firstsearchisawaytonavigateagraphfromaninitialvertexbyvisitingalltheadjacentnodesfirst.



Let’sseehowwecanaccomplishthisincode:

Graph.bfsFullCode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
*bfs(first){
constvisited=newMap();
constvisitList=newQueue();
visitList.add(first);
while(!visitList.isEmpty()){
constnode=visitList.remove();
if(node&&!visited.has(node)){
yieldnode;
visited.set(node);
node.getAdjacents().forEach(adj=>visitList.add(adj));
}
}
}
AsyoucanseeweareusingaQueuewherethefirstnodein,isalsothefirstnodetobevisited(FIFO).

WearealsousingJavaScriptgenerators,noticethe*infrontofthefunction.Weareusingageneratortoiterateonevalueatatime.That’susefulforlargegraphs(millionsofnodes)becauseinmostcasesyoudon’tneedtovisiteverysinglenode.

ThisanexampleofhowtousetheBFSthatwejustcreated:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
constgraph=newGraph(Graph.UNDIRECTED);
const[first]=graph.addEdge(1,2);
graph.addEdge(1,3);
graph.addEdge(1,4);
graph.addEdge(5,2);
graph.addEdge(6,3);
graph.addEdge(7,3);
graph.addEdge(8,4);
graph.addEdge(9,5);
graph.addEdge(10,6);
bfsFromFirst=graph.bfs(first);
bfsFromFirst.next().value.value;//1
bfsFromFirst.next().value.value;//2
bfsFromFirst.next().value.value;//3
bfsFromFirst.next().value.value;//4
//...
Youcanfindmoreexamplesofusageinthetestcases.Let’smoveontotheDFS!

Depth-firstsearch(DFS)-Graphsearch

Depth-firstsearchisanotherwaytonavigateagraphfromaninitialvertexbyrecursivelythefirstadjacentnodeofeachvertexfound.



TheiterativeimplementationofaDFSisidenticaltotheBFS,butinsteadofusingaQueueyouuseaStack:

Graph.dfsFullCode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
*dfs(first){
constvisited=newMap();
constvisitList=newStack();
visitList.add(first);
while(!visitList.isEmpty()){
constnode=visitList.remove();
if(node&&!visited.has(node)){
yieldnode;
visited.set(node);
node.getAdjacents().forEach(adj=>visitList.add(adj));
}
}
}
Wecantestourgraphasfollow.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
constgraph=newGraph(Graph.UNDIRECTED);
const[first]=graph.addEdge(1,2);
graph.addEdge(1,3);
graph.addEdge(1,4);
graph.addEdge(5,2);
graph.addEdge(6,3);
graph.addEdge(7,3);
graph.addEdge(8,4);
graph.addEdge(9,5);
graph.addEdge(10,6);
dfsFromFirst=graph.dfs(first);
visitedOrder=Array.from(dfsFromFirst);
constvalues=visitedOrder.map(node=>node.value);
console.log(values);//[1,4,8,3,7,6,10,2,5,9]
AsyoucanseethegraphisthesameonBFSandDFS,however,theorderhowthenodeswerevisitedisverydifferent.BFSwentfrom1to10inthatorder,whileDFSwentasdeepasitcouldoneachnode.

GraphTimeandSpaceComplexity

WehaveseensomeofthebasicoperationsofaGraph.Howtoaddandremoveverticesandedges.Here’sasummaryofwhatwehavecoveredsofar:

AdjacencyListAdjacencyMatrix
SpaceO(|V|+|E|)O(|V|2)
addVertexO(1)O(|V|2)
removeVertexO(|V|+|E|)O(|V|2)
addEdgeO(1)O(1)
removeEdge(usingArray)O(|E|)O(1)
removeEdge(usingHashSet)O(1)O(1)
getAdjacentsO(|E|)O(|V|)
isAdjacent(usingArray)O(|E|)O(1)
isAdjacent(usingHashSet)O(1)O(1)
Asyoucansee,anadjacencylistisfasterinalmostallfunctions.Theonlythattheadjacencymatrixwilloutperformtheadjacencylistischeckingifanodeisadjacenttoother,however,ifwechangeourimplementationfromArraytoaHashSetwecangetitinconstanttimeaswell:)

Summary

Aswesaw,Graphscanhelptomodelmanyreal-lifescenariossuchasairports,socialnetworks,internetandsoon.WecoveredsomeofmostbasicalgorithmssuchasBreadth-FirstSearch(BFS)andDepth-FirstSearch(DFS).Also,wetalkaboutimplementationstrade-offssuchasadjacencylistandmatrix.Therearemanyotherapplicationsthatwearegoingtocoverinanotherpostsuchasfindingtheshortestpathbetweennodesanddifferentexcitinggraphalgorithms.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Visited Go