Dijkstra算法(Swift版)
阿新 • • 發佈:2017-11-16
map 數組 double sta weight lte turn man 最短
原理
我們知道,使用Breadth-first search算法能夠找到到達某個目標的最短路徑,但這個算法沒考慮weight
,因此我們再為每個edge添加了權重後,我們就需要使用Dijkstra算法來尋找權重和最小的路徑。
其實原理很簡單,我們最終的目的是計算出每一個節點到起點的權重之和,同時獲取得到這個權重和的路徑數組。
那麽權重和最小的那個自然就是我們要的結果。
在該算法中有一下幾個核心的思想:
- 當我們遍歷到某個節點時,計算出該節點到起點的權重和之後=,該節點就不在使用了,或刪除或者標記為已檢閱
- 當該節點的某個neighbor節點加上權重的值小於該neighbor節點時,跟新該neighbor節點的數據
實現這個算法的方式有多種,在該文章中,我們把某些數據直接封裝到了節點中。
Vertex
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
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: " -> "))
}
打印結果:
(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
主要代碼來自於Dijkstra
Dijkstra算法(Swift版)