SwiftGraph is a pure Swift (no Cocoa) implementation of a graph data structure, appropriate for use on all platforms Swift supports (iOS, OS X, Linux, etc.). It includes support for weighted, unweighted, directed, and undirected graphs. It uses generics to abstract away both the type of the vertices, and the type of the weights.
It includes copious in-source documentation, some unit tests, as well as utility functions for doing things like breadth-first search, depth-first search, and dijkstra's algorithm. It has appeared as a dependency in multiple open source projects, but lacks robust testing with large datasets.
SwiftGraph 1.1.0 and above requires Swift 3 (Xcode 8). SwiftGraph 1.0.1 through 1.0.6 requires Swift 2 (Xcode 7). For Swift 1.2 support (Xcode 6.3) use version 1.0 of SwiftGraph.
Use the CocoaPod SwiftGraph
.
Use this repository as your dependency.
Copy all of the sources in the Sources
folder into your project.
- To get a sense of how to use SwiftGraph, checkout the unit tests
- Inserting an edge by vertex indices is much faster than inserting an edge by vertex objects that need to have their indices looked up
- Generally, looking for the index of a vertex is O(n) time, with n being the number of vertices in the graph
- SwiftGraph includes the functions
bfs()
anddfs()
for finding a route between one vertex and another in a graph anddijkstra()
for finding shortest paths in a weighted graph - Is the sample program (Nine Tails) beachballing and taking a few seconds to load for you? Edit the Run scheme to be Release instead of Debug
There is a large amount of documentation in the source code using the latest Apple documentation technique - so you should be able to just alt-click a method name to get a lot of great information about it in Xcode. There are up-to-date HTML docs available online thanks to the good folks at CocoaPods In addition, here's some more basic information:
Edges connect the vertices in your graph to one another.
Edge
(Protocol) - A protocol that all edges in a graph must conform to. An edge is a connection between two vertices in the graph. The vertices are specified by their index in the graph which is an integer. Further, an edge knows if it's directed, or weighted. An edge can create a reversed version of itself.UnweightedEdge
- This is a concrete implementation ofEdge
for unweighted graphs.WeightedEdge
- A subclass ofUnweightedEdge
that adds weights. Weights are a generic type - they can be anything that implementsComparable
andSummable
.Summable
is anything that implements the+
operator. To addSummable
support to a data type that already has the plus operator, simply write something like (support in SwiftGraph is already included forInt
,Float
,Double
, andString
):
extension Int: Summable {}
Graphs are the data structures at the heart of SwiftGraph. All vertices are assigned an integer index when they are inserted into a graph and it's generally faster to refer to them by their index than by the vertex's actual object.
Graphs implement the standard Swift protocols SequenceType
(for iterating through all vertices) and CollectionType
(for grabbing a vertex by its index through a subscript). For instance, the following example prints all vertices in a Graph on separate lines:
for v in g { // g is a Graph<String>
println(v)
}
And we can grab a specific vertex by its index using a subscript
println(g[23]) // g is a Graph<String>
Note: At this time, graphs are not thread-safe. However, once a graph is constructed, if you will only be doing lookups and searches through it (no removals of vertices/edges and no additions of vertices/edges) then you should be able to do that from multiple threads. A fully thread-safe graph implementation is a possible future direction.
Graph
- This is the base class for all graphs. Generally, you should use one of its canonical subclasses,UnweightedGraph
orWeightedGraph
, because they offer more functionality. The vertices in aGraph
(defined as a generic at graph creation time) can be of any type that conforms toEquatable
.Graph
has methods for:- Adding a vertex
- Getting the index of a vertex
- Finding the neighbors of an index/vertex
- Finding the edges of an index/vertex
- Checking if an edge from one index/vertex to another index/vertex exists
- Checking if a vertex is in the graph
- Adding an edge
- Removing all edges between two indexes/vertices
- Removing a particular vertex (all other edge relationships are automatically updated at the same time (because the indices of their connections changes) so this is slow - O(v + e) where v is the number of vertices and e is the number of edges)
UnweightedGraph
- A subclass ofGraph
that adds convenience methods for adding and removing edges of typeUnweightedEdge
.WeightedGraph
- A subclass ofGraph
that adds convenience methods for adding and removing edges of typeWeightedEdge
.WeightedGraph
also adds a method for returning a list of tuples containing all of the neighbor vertices of an index along with their respective weights.
bfs()
- Finds a path from one vertex to another in aGraph
using a breadth-first search. Returns an array ofEdge
s going from the source vertex to the destination vertex or an empty array if no path could be found.dfs()
- Finds a path from one vertex to another in aGraph
using a depth-first search. Returns an array ofEdge
s going from the source vertex to the destination vertex or an empty array if no path could be found.dijkstra()
- Finds the shortest path from a starting vertex to every other vertex in aWeightedGraph
. Returns a tuple who's first element is an array of the distances to each vertex in the graph arranged by index. The second element of the tuple is a dictionary mapping graph indices to the previousEdge
that gets them there in the shortest time from the staring vertex. Using this dictionary and the functionpathDictToPath()
, you can find the shortest path from the starting vertex to any other connected vertex. See thedijkstra()
unit tests inDijkstraGraphTests.swift
for a demo of this.
SwiftGraph is written by David Kopec and released under the Apache License (see LICENSE
). You can find my email address on my GitHub profile page. I encourage you to submit pull requests and open issues here on GitHub.
Future directions for this project to take could include:
- Improved performance
- More extensive performance testing