Skip to content

Commit 495303b

Browse files
committed
refactor Graph implementation
- define an abstract class called AbstractGraph, with two concrete implementations: AdjacencyListGraph and AdjacencyMatrixGraph - improve some method naming, especially those dealing with creating (un)directed edges - make a framework target, and add xcodeproj and playground to a workspace to import the framework module so we don't need to duplicate the implementation in the playground - update README to reflect the new implementations/concepts consequently, the APSP implementation is updated to use the refactored Graph implementation, plus: - improvements to doc comments - remove redundant parameter in FloydWarshallResult.recursePathFrom - changed the test case ported from the book to reflect the exact names of the graph vertices
1 parent 2b58f9f commit 495303b

33 files changed

+1434
-536
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
//: Playground - noun: a place where people can play
22

3+
import Graph
34
import APSP
45

5-
var graph = Graph<String>()
6+
var graph = AdjacencyListGraph<String>()
67

78
let v1 = graph.createVertex("Montreal")
89
let v2 = graph.createVertex("New York")
910
let v3 = graph.createVertex("Boston")
1011
let v4 = graph.createVertex("Portland")
1112
let v5 = graph.createVertex("Portsmouth")
1213

13-
graph.connect(v1, to: v2, withWeight: 3)
14-
graph.connect(v1, to: v5, withWeight: -4)
15-
graph.connect(v1, to: v3, withWeight: 8)
14+
graph.addDirectedEdge(v1, to: v2, withWeight: 3)
15+
graph.addDirectedEdge(v1, to: v5, withWeight: -4)
16+
graph.addDirectedEdge(v1, to: v3, withWeight: 8)
1617

17-
graph.connect(v2, to: v4, withWeight: 1)
18-
graph.connect(v2, to: v5, withWeight: 7)
18+
graph.addDirectedEdge(v2, to: v4, withWeight: 1)
19+
graph.addDirectedEdge(v2, to: v5, withWeight: 7)
1920

20-
graph.connect(v3, to: v2, withWeight: 4)
21+
graph.addDirectedEdge(v3, to: v2, withWeight: 4)
2122

22-
graph.connect(v4, to: v1, withWeight: 2)
23-
graph.connect(v4, to: v3, withWeight: -5)
23+
graph.addDirectedEdge(v4, to: v1, withWeight: 2)
24+
graph.addDirectedEdge(v4, to: v3, withWeight: -5)
2425

25-
graph.connect(v5, to: v4, withWeight: 6)
26+
graph.addDirectedEdge(v5, to: v4, withWeight: 6)
2627

2728
let result = FloydWarshall<String>.apply(graph)
2829

29-
let path = result.path(fromVertex: v1, toVertex: v4, inGraph: graph)
30+
let path = result.path(fromVertex: v1, toVertex: v4, inGraph: graph)

All-Pairs Shortest Paths/APSP/APSP.playground/timeline.xctimeline

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
version = "3.0">
44
<TimelineItems>
55
<LoggerValueHistoryTimelineItem
6-
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=790&amp;EndingColumnNumber=44&amp;EndingLineNumber=28&amp;StartingColumnNumber=3&amp;StartingLineNumber=27&amp;Timestamp=484286078.350375"
6+
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=888&amp;EndingColumnNumber=44&amp;EndingLineNumber=29&amp;StartingColumnNumber=3&amp;StartingLineNumber=28&amp;Timestamp=486844329.035763"
77
selectedRepresentationIndex = "0"
88
shouldTrackSuperviewWidth = "NO">
99
</LoggerValueHistoryTimelineItem>
1010
<LoggerValueHistoryTimelineItem
11-
documentLocation = "#CharacterRangeLen=4&amp;CharacterRangeLoc=727&amp;EndingColumnNumber=9&amp;EndingLineNumber=28&amp;StartingColumnNumber=5&amp;StartingLineNumber=28&amp;Timestamp=484286078.357412"
11+
documentLocation = "#CharacterRangeLen=4&amp;CharacterRangeLoc=825&amp;EndingColumnNumber=9&amp;EndingLineNumber=29&amp;StartingColumnNumber=5&amp;StartingLineNumber=29&amp;Timestamp=486844329.036018"
1212
selectedRepresentationIndex = "0"
1313
shouldTrackSuperviewWidth = "NO">
1414
</LoggerValueHistoryTimelineItem>

All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj

+68-18
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,37 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
491AA3821CE8C5F700A2E2C5 /* Graph.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 491AA37F1CE8C5C900A2E2C5 /* Graph.framework */; };
1011
493D8DE31CDD2A1C0089795A /* APSPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 493D8DE21CDD2A1C0089795A /* APSPTests.swift */; };
1112
493D8DF41CDD5B960089795A /* APSP.h in Headers */ = {isa = PBXBuildFile; fileRef = 493D8DF31CDD5B960089795A /* APSP.h */; settings = {ATTRIBUTES = (Public, ); }; };
1213
493D8DF91CDD5B9B0089795A /* FloydWarshall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 493D8DD81CDC38C60089795A /* FloydWarshall.swift */; };
1314
493D8DFA1CDD5B9E0089795A /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 493D8DDA1CDD29C80089795A /* Helpers.swift */; };
14-
493D8DFB1CDD5BDE0089795A /* AdjacencyMatrix.swift in Sources */ = {isa = PBXBuildFile; fileRef = 493D8DB91CDC34D00089795A /* AdjacencyMatrix.swift */; };
1515
49BFA27A1CDD93F400522D66 /* APSP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49BFA2791CDD93F400522D66 /* APSP.swift */; };
1616
49BFA2801CDE742900522D66 /* APSP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 493D8DF11CDD5B960089795A /* APSP.framework */; };
1717
/* End PBXBuildFile section */
1818

1919
/* Begin PBXContainerItemProxy section */
20+
491AA37E1CE8C5C900A2E2C5 /* PBXContainerItemProxy */ = {
21+
isa = PBXContainerItemProxy;
22+
containerPortal = 491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */;
23+
proxyType = 2;
24+
remoteGlobalIDString = 49BFA2FD1CDF886B00522D66;
25+
remoteInfo = Graph;
26+
};
27+
491AA3801CE8C5C900A2E2C5 /* PBXContainerItemProxy */ = {
28+
isa = PBXContainerItemProxy;
29+
containerPortal = 491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */;
30+
proxyType = 2;
31+
remoteGlobalIDString = 49BFA3071CDF886B00522D66;
32+
remoteInfo = GraphTests;
33+
};
34+
491AA3831CE8C5F900A2E2C5 /* PBXContainerItemProxy */ = {
35+
isa = PBXContainerItemProxy;
36+
containerPortal = 491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */;
37+
proxyType = 1;
38+
remoteGlobalIDString = 49BFA2FC1CDF886B00522D66;
39+
remoteInfo = Graph;
40+
};
2041
49BFA27E1CDE742700522D66 /* PBXContainerItemProxy */ = {
2142
isa = PBXContainerItemProxy;
2243
containerPortal = 493D8D7E1CDC2DAE0089795A /* Project object */;
@@ -27,7 +48,7 @@
2748
/* End PBXContainerItemProxy section */
2849

2950
/* Begin PBXFileReference section */
30-
493D8DB91CDC34D00089795A /* AdjacencyMatrix.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdjacencyMatrix.swift; sourceTree = "<group>"; };
51+
491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Graph.xcodeproj; path = ../../Graph/Graph.xcodeproj; sourceTree = "<group>"; };
3152
493D8DD81CDC38C60089795A /* FloydWarshall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloydWarshall.swift; sourceTree = "<group>"; };
3253
493D8DDA1CDD29C80089795A /* Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
3354
493D8DE01CDD2A1C0089795A /* APSPTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = APSPTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -52,16 +73,26 @@
5273
isa = PBXFrameworksBuildPhase;
5374
buildActionMask = 2147483647;
5475
files = (
76+
491AA3821CE8C5F700A2E2C5 /* Graph.framework in Frameworks */,
5577
);
5678
runOnlyForDeploymentPostprocessing = 0;
5779
};
5880
/* End PBXFrameworksBuildPhase section */
5981

6082
/* Begin PBXGroup section */
83+
491AA37A1CE8C5C900A2E2C5 /* Products */ = {
84+
isa = PBXGroup;
85+
children = (
86+
491AA37F1CE8C5C900A2E2C5 /* Graph.framework */,
87+
491AA3811CE8C5C900A2E2C5 /* GraphTests.xctest */,
88+
);
89+
name = Products;
90+
sourceTree = "<group>";
91+
};
6192
493D8D7D1CDC2DAE0089795A = {
6293
isa = PBXGroup;
6394
children = (
64-
493D8DB71CDC34D00089795A /* Graph */,
95+
491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */,
6596
493D8D881CDC2DAE0089795A /* APSP */,
6697
493D8DE11CDD2A1C0089795A /* APSPTests */,
6798
493D8D871CDC2DAE0089795A /* Products */,
@@ -89,15 +120,6 @@
89120
path = APSP;
90121
sourceTree = "<group>";
91122
};
92-
493D8DB71CDC34D00089795A /* Graph */ = {
93-
isa = PBXGroup;
94-
children = (
95-
493D8DB91CDC34D00089795A /* AdjacencyMatrix.swift */,
96-
);
97-
name = Graph;
98-
path = ../../Graph;
99-
sourceTree = "<group>";
100-
};
101123
493D8DE11CDD2A1C0089795A /* APSPTests */ = {
102124
isa = PBXGroup;
103125
children = (
@@ -151,6 +173,7 @@
151173
buildRules = (
152174
);
153175
dependencies = (
176+
491AA3841CE8C5F900A2E2C5 /* PBXTargetDependency */,
154177
);
155178
name = APSP;
156179
productName = APSP;
@@ -165,7 +188,7 @@
165188
attributes = {
166189
LastSwiftUpdateCheck = 0730;
167190
LastUpgradeCheck = 0730;
168-
ORGANIZATIONNAME = "Andrew McKnight";
191+
ORGANIZATIONNAME = "Swift Algorithm Club";
169192
TargetAttributes = {
170193
493D8DDF1CDD2A1C0089795A = {
171194
CreatedOnToolsVersion = 7.3;
@@ -185,6 +208,12 @@
185208
mainGroup = 493D8D7D1CDC2DAE0089795A;
186209
productRefGroup = 493D8D871CDC2DAE0089795A /* Products */;
187210
projectDirPath = "";
211+
projectReferences = (
212+
{
213+
ProductGroup = 491AA37A1CE8C5C900A2E2C5 /* Products */;
214+
ProjectRef = 491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */;
215+
},
216+
);
188217
projectRoot = "";
189218
targets = (
190219
493D8DDF1CDD2A1C0089795A /* APSPTests */,
@@ -193,6 +222,23 @@
193222
};
194223
/* End PBXProject section */
195224

225+
/* Begin PBXReferenceProxy section */
226+
491AA37F1CE8C5C900A2E2C5 /* Graph.framework */ = {
227+
isa = PBXReferenceProxy;
228+
fileType = wrapper.framework;
229+
path = Graph.framework;
230+
remoteRef = 491AA37E1CE8C5C900A2E2C5 /* PBXContainerItemProxy */;
231+
sourceTree = BUILT_PRODUCTS_DIR;
232+
};
233+
491AA3811CE8C5C900A2E2C5 /* GraphTests.xctest */ = {
234+
isa = PBXReferenceProxy;
235+
fileType = wrapper.cfbundle;
236+
path = GraphTests.xctest;
237+
remoteRef = 491AA3801CE8C5C900A2E2C5 /* PBXContainerItemProxy */;
238+
sourceTree = BUILT_PRODUCTS_DIR;
239+
};
240+
/* End PBXReferenceProxy section */
241+
196242
/* Begin PBXResourcesBuildPhase section */
197243
493D8DDE1CDD2A1C0089795A /* Resources */ = {
198244
isa = PBXResourcesBuildPhase;
@@ -226,13 +272,17 @@
226272
49BFA27A1CDD93F400522D66 /* APSP.swift in Sources */,
227273
493D8DF91CDD5B9B0089795A /* FloydWarshall.swift in Sources */,
228274
493D8DFA1CDD5B9E0089795A /* Helpers.swift in Sources */,
229-
493D8DFB1CDD5BDE0089795A /* AdjacencyMatrix.swift in Sources */,
230275
);
231276
runOnlyForDeploymentPostprocessing = 0;
232277
};
233278
/* End PBXSourcesBuildPhase section */
234279

235280
/* Begin PBXTargetDependency section */
281+
491AA3841CE8C5F900A2E2C5 /* PBXTargetDependency */ = {
282+
isa = PBXTargetDependency;
283+
name = Graph;
284+
targetProxy = 491AA3831CE8C5F900A2E2C5 /* PBXContainerItemProxy */;
285+
};
236286
49BFA27F1CDE742700522D66 /* PBXTargetDependency */ = {
237287
isa = PBXTargetDependency;
238288
target = 493D8DF01CDD5B960089795A /* APSP */;
@@ -329,7 +379,7 @@
329379
COMBINE_HIDPI_IMAGES = YES;
330380
INFOPLIST_FILE = APSPTests/Info.plist;
331381
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
332-
PRODUCT_BUNDLE_IDENTIFIER = com.armcknight.APSPTests;
382+
PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSPTests";
333383
PRODUCT_NAME = "$(TARGET_NAME)";
334384
};
335385
name = Debug;
@@ -340,7 +390,7 @@
340390
COMBINE_HIDPI_IMAGES = YES;
341391
INFOPLIST_FILE = APSPTests/Info.plist;
342392
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
343-
PRODUCT_BUNDLE_IDENTIFIER = com.armcknight.APSPTests;
393+
PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSPTests";
344394
PRODUCT_NAME = "$(TARGET_NAME)";
345395
};
346396
name = Release;
@@ -358,7 +408,7 @@
358408
INFOPLIST_FILE = APSP/Info.plist;
359409
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
360410
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
361-
PRODUCT_BUNDLE_IDENTIFIER = com.armcknight.APSP;
411+
PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP";
362412
PRODUCT_NAME = "$(TARGET_NAME)";
363413
SKIP_INSTALL = YES;
364414
VERSIONING_SYSTEM = "apple-generic";
@@ -379,7 +429,7 @@
379429
INFOPLIST_FILE = APSP/Info.plist;
380430
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
381431
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
382-
PRODUCT_BUNDLE_IDENTIFIER = com.armcknight.APSP;
432+
PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP";
383433
PRODUCT_NAME = "$(TARGET_NAME)";
384434
SKIP_INSTALL = YES;
385435
VERSIONING_SYSTEM = "apple-generic";

All-Pairs Shortest Paths/APSP/APSP/APSP.h

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// APSP
44
//
55
// Created by Andrew McKnight on 5/6/16.
6-
// Copyright © 2016 Andrew McKnight. All rights reserved.
76
//
87

98
#import <Cocoa/Cocoa.h>

All-Pairs Shortest Paths/APSP/APSP/APSP.swift

+9-9
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,31 @@
33
// APSP
44
//
55
// Created by Andrew McKnight on 5/6/16.
6-
// Copyright © 2016 Andrew McKnight. All rights reserved.
76
//
87

98
import Foundation
9+
import Graph
1010

1111
/**
12-
APSPAlgorithm is a protocol for encapsulating an All-Pairs Shortest Paths algorithm. It provides a single function `apply` that accepts a `Graph` and returns an object conforming to `APSPResult`.
12+
`APSPAlgorithm` is a protocol for encapsulating an All-Pairs Shortest Paths algorithm. It provides a single function `apply` that accepts a subclass of `AbstractGraph` and returns an object conforming to `APSPResult`.
1313
*/
14-
protocol APSPAlgorithm {
14+
public protocol APSPAlgorithm {
1515

16-
associatedtype Q
16+
associatedtype Q: Hashable
1717
associatedtype P: APSPResult
1818

19-
static func apply(graph: Graph<Q>) -> P
19+
static func apply(graph: AbstractGraph<Q>) -> P
2020

2121
}
2222

2323
/**
24-
APSPResult is a protocol defining functions `distance` and `path`, allowing for opaque queries into the actual data structures that represent the APSP solution according to the algorithm used.
24+
`APSPResult` is a protocol defining functions `distance` and `path`, allowing for opaque queries into the actual data structures that represent the APSP solution according to the algorithm used.
2525
*/
26-
protocol APSPResult {
26+
public protocol APSPResult {
2727

28-
associatedtype T
28+
associatedtype T: Hashable
2929

3030
func distance(fromVertex from: Vertex<T>, toVertex to: Vertex<T>) -> Double?
31-
func path(fromVertex from: Vertex<T>, toVertex to: Vertex<T>, inGraph graph: Graph<T>) -> [T]?
31+
func path(fromVertex from: Vertex<T>, toVertex to: Vertex<T>, inGraph graph: AbstractGraph<T>) -> [T]?
3232

3333
}

0 commit comments

Comments
 (0)