咱們知道,使用Breadth-first search算法可以找到到達某個目標的最短路徑,但這個算法沒考慮weight
,所以咱們再爲每一個edge添加了權重後,咱們就須要使用Dijkstra算法來尋找權重和最小的路徑。git
其實原理很簡單,咱們最終的目的是計算出每個節點到起點的權重之和,同時獲取獲得這個權重和的路徑數組。
那麼權重和最小的那個天然就是咱們要的結果。github
在該算法中有一下幾個核心的思想:算法
實現這個算法的方式有多種,在該文章中,咱們把某些數據直接封裝到了節點中。swift
Vertex.swift import Foundation open class Vertex { open var identifier: String open var neighbors: [(Vertex, Double)] = [] open var pathLengthFromStart = Double.infinity open var pathVerticesFromStart: [Vertex] = [] public init(identifier: String) { self.identifier = identifier } open func clearCache() { pathLengthFromStart = Double.infinity pathVerticesFromStart = [] } } extension Vertex: Hashable { open var hashValue: Int { return identifier.hashValue } } extension Vertex: Equatable { public static func ==(lhs: Vertex, rhs: Vertex) -> Bool { return lhs.hashValue == rhs.hashValue } }
Dijkstra.swift import Foundation public class Dijkstra { private var totalVertices: Set<Vertex> public init(vertices: Set<Vertex>) { totalVertices = vertices } private func clearCache() { totalVertices.forEach { $0.clearCache() } } public func findShortestPaths(from startVertex: Vertex) { clearCache() var currentVertices = self.totalVertices startVertex.pathLengthFromStart = 0 startVertex.pathVerticesFromStart.append(startVertex) var currentVertex: Vertex? = startVertex while let vertex = currentVertex { currentVertices.remove(vertex) let filteredNeighbors = vertex.neighbors.filter { currentVertices.contains($0.0) } for neighbor in filteredNeighbors { let neighborVertex = neighbor.0 let weight = neighbor.1 let theoreticNewWeight = vertex.pathLengthFromStart + weight if theoreticNewWeight < neighborVertex.pathLengthFromStart { neighborVertex.pathLengthFromStart = theoreticNewWeight neighborVertex.pathVerticesFromStart = vertex.pathVerticesFromStart neighborVertex.pathVerticesFromStart.append(neighborVertex) } } if currentVertices.isEmpty { currentVertex = nil break } currentVertex = currentVertices.min { $0.pathLengthFromStart < $1.pathLengthFromStart } } } }
咱們就演示這個例子數組
//: Playground - noun: a place where people can play import Foundation // last checked with Xcode 9.0b4 #if swift(>=4.0) print("Hello, Swift 4!") #endif var vertices: Set<Vertex> = Set() /// Create vertexs var vertexA = Vertex(identifier: "A") var vertexB = Vertex(identifier: "B") var vertexC = Vertex(identifier: "C") var vertexD = Vertex(identifier: "D") var vertexE = Vertex(identifier: "E") var vertexF = Vertex(identifier: "F") /// Setting neighbors vertexA.neighbors.append(contentsOf: [(vertexB, 5), (vertexD, 2)]) vertexB.neighbors.append(contentsOf: [(vertexC, 4), (vertexE, 2)]) vertexC.neighbors.append(contentsOf: [(vertexE, 6), (vertexF, 3)]) vertexD.neighbors.append(contentsOf: [(vertexB, 8), (vertexE, 7)]) vertexE.neighbors.append(contentsOf: [(vertexF, 1)]) vertices.insert(vertexA) vertices.insert(vertexB) vertices.insert(vertexC) vertices.insert(vertexD) vertices.insert(vertexE) vertices.insert(vertexF) let dijkstra = Dijkstra(vertices: vertices) dijkstra.findShortestPaths(from: vertexA) for vertex in vertices { let paths = vertex.pathVerticesFromStart.map({ $0.identifier }) print("(A=>" + vertex.identifier + "): " + paths.joined(separator: " -> ")) }
打印結果:app
(A=>B): A -> B (A=>A): A (A=>F): A -> B -> E -> F (A=>C): A -> B -> C (A=>D): A -> D (A=>E): A -> B -> E
主要代碼來自於Dijkstraless