liveBook · Manning

Unweighted graph

As explained in Classic Computer Science Problems in Swift: Essential techniques for practicing programmers

An unweighted graph is a graph whose edges do not have numerical costs or distances.

An unweighted graph records which vertices are connected without assigning numerical costs or distances to its edges. A path is therefore evaluated by its number of edges, not by a sum of weights. section 4.1 section 4.2

A practical Swift representation uses:

  • An adjacency-list array, where each vertex index stores its incident edges. section 4.1
  • An UnweightedEdge containing from and to vertex indices, plus a reversed edge for bidirectional connections. section 4.1
  • An UnweightedGraph whose vertices are Equatable values and whose edges use UnweightedEdge. section 4.1
  • A convenience addEdge operation that inserts both directions for an undirected connection. section 4.1

Hyperloop network

A city graph connects Seattle to Chicago and San Francisco, then links the remaining cities through similar connections. Asking for the shortest route from Boston to Miami produces Boston > Detroit > Washington > Miami: three edges, regardless of any real-world distance. section 4.1 section 4.2

open class UnweightedGraph<V: Equatable>: Graph {
    var vertices: [V] = [V]()
    var edges: [[UnweightedEdge]] = [[UnweightedEdge]]() //adjacency lists

    public init() {
    }

    public init(vertices: [V]) {
        for vertex in vertices {
            _ = self.addVertex(vertex)
        }
    }

    /// This is a convenience method that adds an unweighted edge.
    ///
    /// - parameter from: The starting vertex's index.
    /// - parameter to: The ending vertex's index.
    public func addEdge(from: Int, to: Int) {
        addEdge(UnweightedEdge(u: from, v: to))
    }

    /// This is a convenience method that adds an unweighted, undirected
         edge between the first occurrence of two vertices.
    ///
    /// - parameter from: The starting vertex.
    /// - parameter to: The ending vertex.
    public func addEdge(from: V, to: V) {
        if let u = indexOfVertex(from) {
            if let v = indexOfVertex(to) {
                addEdge(UnweightedEdge(u: u, v: v))
            }
        }
    }

    /// MARK: Implement CustomStringConvertible
    public var description: String {
        var d: String = ""
        for i in 0..<vertices.count {
            d += "\(vertices[i]) -> \(neighborsForIndex(i))\n"
        }
        return d
    }
}

Inspect the concrete Swift graph type and its vertex- and index-based edge helpers. section 4.1

extension Graph {
    //returns a path to the goal vertex
    func bfs(initialVertex: VertexType, goalTestFn:
     (VertexType) -> Bool) -> Path? {
        guard let startIndex = indexOfVertex(initialVertex)
         else { return nil }
        // frontier is where we've yet to go
        let frontier: Queue<Int> = Queue<Int>()
        frontier.push(startIndex)
        // explored is where we've been
        var explored: Set<Int> = Set<Int>()
        explored.insert(startIndex)
        // how did we get to each vertex
        var pathDict: [Int: EdgeType] = [Int: EdgeType]()
        // keep going while there is more to explore
        while !frontier.isEmpty {
            let currentIndex = frontier.pop()
            let currentVertex = vertexAtIndex(currentIndex)
            // if we found the goal, we're done
            if goalTestFn(currentVertex) {
                return pathDictToPath(from: startIndex, to: currentIndex,
                 pathDict: pathDict)
            }
            // check where we can go next and haven't explored
            for edge in edgesForIndex(currentIndex)
             where !explored.contains(edge.v) {
                explored.insert(edge.v)
                frontier.push(edge.v)
                pathDict[edge.v] = edge
            }
        }
        return nil // never found the goal
    }
}

Use breadth-first search to find a shortest path by exploring vertices in increasing edge distance. section 4.2

How Classic Computer Science Problems in Swift: Essential techniques for practicing programmers covers it

How deep it goes
Defines edges and adjacency-list storage, implements Swift types, and applies BFS without treating weighted costs.
Examples
Uses a Hyperloop-style city network and computes the Boston-to-Miami route through Detroit and Washington.
What it assumes
Assumes familiarity with vertices, edges, arrays, and breadth-first search while adapting maze-style search to graph indices.
What you can do after
Build it from scratch in Swift and find fewest-edge routes with breadth-first search.
How it connects
Connects graph representation with adjacency lists, breadth-first search, queues, paths, and shortest-path problems.

Also explained in

Compare how 3 books explain unweighted graph →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Classic Computer Science Problems in Swift: Essential techniques for practicing programmers. The section links point to the parts of the book it draws on.