Skip to content

Instantly share code, notes, and snippets.

@davidinga
Created August 25, 2019 03:04
Show Gist options
  • Save davidinga/56ead53a4a5045cdbad56945a8de30b4 to your computer and use it in GitHub Desktop.
Save davidinga/56ead53a4a5045cdbad56945a8de30b4 to your computer and use it in GitHub Desktop.
Graph data structure in Swift using Objects and Pointers with an Adjacency List.
public enum EdgeType {
case directed, undirected
}
public struct Edge<Element: Hashable> {
var source: Vertex<Element>
var destination: Vertex<Element>
var weight: Double?
}
extension Edge: Hashable {
public static func ==(lhs: Edge, rhs: Edge) -> Bool {
return lhs.source == rhs.source && lhs.destination == rhs.destination && lhs.weight == rhs.weight
}
public func hash(into hasher: inout Hasher) {
hasher.combine(source)
hasher.combine(destination)
hasher.combine(weight)
}
}
protocol Graphable {
associatedtype Element: Hashable
var description: CustomStringConvertible { get }
func createVertex(data: Element) -> Vertex<Element>
func add(_ type: EdgeType, from source: Vertex<Element>, to destination: Vertex<Element>, weight: Double?)
func weight(from source: Vertex<Element>, to destination: Vertex<Element>) -> Double?
func edges(from source: Vertex<Element>) -> [Edge<Element>]?
}
open class GraphOP<Element: Hashable> {
public var adjacencyDict: [Vertex<Element>: [Edge<Element>]] = [:]
public init() {}
fileprivate func addDirectedEdge(from source: Vertex<Element>,
to destination: Vertex<Element>,
weight: Double?) {
let edge = Edge(source: source, destination: destination, weight: weight)
adjacencyDict[source]?.append(edge)
}
fileprivate func addUndirectedEdge(vertices: (Vertex<Element>, Vertex<Element>), weight: Double?) {
let (source, destination) = vertices
addDirectedEdge(from: source, to: destination, weight: weight)
addDirectedEdge(from: destination, to: source, weight: weight)
}
}
extension GraphOP: Graphable {
public func createVertex(data: Element) -> Vertex<Element> {
let vertex = Vertex(data: data)
if adjacencyDict[vertex] == nil {
adjacencyDict[vertex] = []
}
return vertex
}
public func add(_ type: EdgeType,
from source: Vertex<Element>,
to destination: Vertex<Element>,
weight: Double?) {
switch type {
case .directed:
addDirectedEdge(from: source, to: destination, weight: weight)
case .undirected:
addUndirectedEdge(vertices: (source, destination), weight: weight)
}
}
public func weight(from source: Vertex<Element>, to destination: Vertex<Element>) -> Double? {
guard let edges = adjacencyDict[source] else {
return nil
}
for edge in edges {
if edge.destination == destination {
return edge.weight
}
}
return nil
}
public func edges(from source: Vertex<Element>) -> [Edge<Element>]? {
return adjacencyDict[source]
}
public var description: CustomStringConvertible {
var result = ""
for (vertex, edges) in adjacencyDict {
var edgeString = ""
for (index, edge) in edges.enumerated() {
if index != edges.count - 1 {
edgeString.append("\(edge.destination), ")
} else {
edgeString.append("\(edge.destination)")
}
}
result.append("\(vertex) ---> [ \(edgeString) ] \n ")
}
return result
}
}
public struct Vertex<Element: Hashable> {
var data: Element
}
extension Vertex: Hashable {
public static func ==(lhs: Vertex, rhs: Vertex) -> Bool {
return lhs.data == rhs.data
}
public func hash(into hasher: inout Hasher) {
hasher.combine(data)
}
}
extension Vertex: CustomStringConvertible {
public var description: String {
return "\(data)"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment