30. Implementation
public struct Vertex<T>: Equatable where T: Hashable {
public var data: T
public let index: Int
}
extension Vertex: CustomStringConvertible {
public var description: String {
return "(index): (data)"
}
}
extension Vertex: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(data)
hasher.combine(index)
}
}
public func ==<T>(lhs: Vertex<T>, rhs: Vertex<T>) -> Bool {
guard lhs.index == rhs.index else {
return false
}
guard lhs.data == rhs.data else {
return false
}
return true
}
31. Implementation
public struct Edge<T>: Equatable where T: Hashable {
public let from: Vertex<T>
public let to: Vertex<T>
public let weight: Double?
}
extension Edge: CustomStringConvertible {
public var description: String {
guard let unwrappedWeight = weight else {
return "(from.description) -> (to.description)"
}
return "(from.description) -((unwrappedWeight))-> (to.description)"
}
}
extension Edge: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(from.description)
hasher.combine(to.description)
hasher.combine(weight)
}
}
public func == <T>(lhs: Edge<T>, rhs: Edge<T>) -> Bool {
guard lhs.from == rhs.from else {
return false
}
guard lhs.to == rhs.to else {
return false
}
guard lhs.weight == rhs.weight else {
return false
}
return true
}
32. Implementation
open class AbstractGraph<T>: CustomStringConvertible where T: Hashable {
public required init() {}
public required init(fromGraph graph: AbstractGraph<T>) {
for edge in graph.edges {
let from = createVertex(edge.from.data)
let to = createVertex(edge.to.data)
addDirectedEdge(from, to: to, withWeight: edge.weight)
}
}
open func createVertex(_ data: T) -> Vertex<T> {
fatalError("abstract function called")
}
open func addDirectedEdge(_ from: Vertex<T>, to: Vertex<T>, withWeight weight: Double?) {
fatalError("abstract function called")
}
open func addUndirectedEdge(_ vertices: (Vertex<T>, Vertex<T>), withWeight weight: Double?) {
fatalError("abstract function called")
}
open func weightFrom(_ sourceVertex: Vertex<T>, to destinationVertex: Vertex<T>) -> Double? {
fatalError("abstract function called")
}
open func edgesFrom(_ sourceVertex: Vertex<T>) -> [Edge<T>] {
fatalError("abstract function called")
}
open var description: String {
fatalError("abstract property accessed")
}
open var vertices: [Vertex<T>] {
fatalError("abstract property accessed")
}
open var edges: [Edge<T>] {
fatalError("abstract property accessed")
}
}
33. Implementation
private class EdgeList<T> where T: Hashable {
var vertex: Vertex<T>
var edges: [Edge<T>]?
init(vertex: Vertex<T>) {
self.vertex = vertex
}
func addEdge(_ edge: Edge<T>) {
edges?.append(edge)
}
}
34. Implementation
open class AdjacencyListGraph<T>: AbstractGraph<T> where T: Hashable {
fileprivate var adjacencyList: [EdgeList<T>] = []
public required init() {
super.init()
}
public required init(fromGraph graph: AbstractGraph<T>) {
super.init(fromGraph: graph)
}
open override var vertices: [Vertex<T>] {
var vertices = [Vertex<T>]()
for edgeList in adjacencyList {
vertices.append(edgeList.vertex)
}
return vertices
}
....
35. Implementation
....
open override var edges: [Edge<T>] {
var allEdges = Set<Edge<T>>()
for edgeList in adjacencyList {
guard let edges = edgeList.edges else {
continue
}
for edge in edges {
allEdges.insert(edge)
}
}
return Array(allEdges)
}
open override func createVertex(_ data: T) -> Vertex<T> {
// check if the vertex already exists
let matchingVertices = vertices.filter { vertex in
return vertex.data == data
}
if matchingVertices.count > 0 {
return matchingVertices.last!
}
// if the vertex doesn't exist, create a new one
let vertex = Vertex(data: data, index: adjacencyList.count)
adjacencyList.append(EdgeList(vertex: vertex))
return vertex
}
.
36. Implementation
....
open override func addDirectedEdge(_ from: Vertex<T>, to: Vertex<T>, withWeight weight: Double?) {
let edge = Edge(from: from, to: to, weight: weight)
let edgeList = adjacencyList[from.index]
if edgeList.edges != nil {
edgeList.addEdge(edge)
} else {
edgeList.edges = [edge]
}
}
open override func addUndirectedEdge(_ vertices: (Vertex<T>, Vertex<T>), withWeight weight:
Double?) {
addDirectedEdge(vertices.0, to: vertices.1, withWeight: weight)
addDirectedEdge(vertices.1, to: vertices.0, withWeight: weight)
}
open override func weightFrom(_ sourceVertex: Vertex<T>, to destinationVertex: Vertex<T>) ->
Double? {
guard let edges = adjacencyList[sourceVertex.index].edges else {
return nil
}
for edge: Edge<T> in edges {
if edge.to == destinationVertex {
return edge.weight
}
}
return nil
}
.
37. Implementation
open override func edgesFrom(_ sourceVertex: Vertex<T>) -> [Edge<T>] {
return adjacencyList[sourceVertex.index].edges ?? []
}
open override var description: String {
var rows = [String]()
for edgeList in adjacencyList {
guard let edges = edgeList.edges else {
continue
}
var row = [String]()
for edge in edges {
var value = "(edge.to.data)"
if edge.weight != nil {
value = "((value): (edge.weight!))"
}
row.append(value)
}
rows.append("(edgeList.vertex.data) -> [(row.joined(separator: ", "))]")
}
return rows.joined(separator: "n")
}
}
38. Implementation
func depthFirstSearch(source: NodeGraph) -> [String] {
var nodesExplored = [source.label]
source.visited = true
for edge in source.neighbors {
if !edge.neighbor.visited {
nodesExplored += depthFirstSearch(source: edge.neighbor)
}
}
return nodesExplored
}
39. Implementation
let graph = Graph()
let nodeA = graph.addNode("A")
let nodeB = graph.addNode("B")
let nodeC = graph.addNode("C")
let nodeD = graph.addNode("D")
let nodeE = graph.addNode("E")
let nodeF = graph.addNode("F")
let nodeG = graph.addNode("G")
let nodeH = graph.addNode("H")
graph.addEdge(nodeA, neighbor: nodeB)
graph.addEdge(nodeA, neighbor: nodeC)
graph.addEdge(nodeB, neighbor: nodeD)
graph.addEdge(nodeB, neighbor: nodeE)
graph.addEdge(nodeC, neighbor: nodeF)
graph.addEdge(nodeC, neighbor: nodeG)
graph.addEdge(nodeE, neighbor: nodeH)
graph.addEdge(nodeE, neighbor: nodeF)
graph.addEdge(nodeF, neighbor: nodeG)
let nodesExplored = depthFirstSearch(source: nodeA)
print(nodesExplored)
// ["A", "B", "D", "E", "H", "F", "G", "C"]
40. Implementation
func depthFirstSearch(start: Int, end lastNode: Int, edges: [(Int, Int)]) -> [Any] {
var edgeInfo = [Int: Array<Int>]()
for edge in edges {
if var array = edgeInfo[edge.0] {
array.append(edge.1)
edgeInfo[edge.0] = array
} else { edgeInfo[edge.0] = [edge.1] }
}
var result = 0
var paths:[[Any]] = [[]]
func dfs(node: Int, visited: [Int]) {
guard node != lastNode else {
if result < lastNode { paths.append(visited) }
result += 1
return
}
guard let neighbors = edgeInfo[node] else { return }
for edge in neighbors {
guard visited.contains(edge) == false else { continue }
dfs(node: edge, visited: visited + [edge])
}
}
dfs(node: start, visited: [1])
return paths.filter { $0.count != 0 }
}