代码实现
(包括图,边,点)
public class DijkstraEdge<T:Equatable & Hashable>:Equatable {
public var from:DijkstraNode<T>
public var to:DijkstraNode<T>
public var weight:Double
public init(weight:Double, from:DijkstraNode<T>, to:DijkstraNode<T>) {
self.weight = weight
self.from = from
self.to = to
from.edges.append(self)
}
}
public func == <T: Equatable> (lhs: DijkstraEdge<T>, rhs: DijkstraEdge<T>) ->
Bool {
guard lhs.from.value == rhs.from.value else {
return false
}
guard lhs.to.value == rhs.to.value else {
return false
}
return true
}
extension DijkstraEdge: Hashable {
public var hashValue: Int {
get {
let stringHash = "\(from.value)->\(to.value)"
return stringHash.hashValue
}
}
}
public class DijkstraNode<T:Equatable & Hashable>:Equatable {
public var value:T
public var edges:[DijkstraEdge<T>]
public var visited:Bool
public var distance:Int = Int.max
public var previous:DijkstraNode<T>?
public init(value:T, edges:[DijkstraEdge<T>], visited:Bool) {
self.value = value
self.edges = edges
self.visited = visited
}
}
public func == <T: Equatable> (lhs: DijkstraNode<T>, rhs: DijkstraNode<T>) -> Bool {
guard lhs.value == rhs.value else {
return false
}
return true
}
extension DijkstraNode: Hashable {
public var hashValue: Int {
get {
return value.hashValue
}
}
}
public class DijkstraGraph<T:Hashable & Equatable> {
public var nodes:[DijkstraNode<T>]
public init(nodes:[DijkstraNode<T>]) {
self.nodes = nodes
}
public static func dijkstraPath(startNode:DijkstraNode<T>,
graph:DijkstraGraph<T>, finishNode:DijkstraNode<T>) {
var unvisitedNodes = Set<DijkstraNode<T>>(graph.nodes)
startNode.distance = 0
var currentNode:DijkstraNode<T> = startNode
while (finishNode.visited == false) {
for edge in currentNode.edges.filter({ (edge) -> Bool in
return edge.to.visited == false
}) {
let temporaryDistance = currentNode.distance +
Int(edge.weight)
if edge.to.distance > temporaryDistance {
edge.to.distance = temporaryDistance
edge.to.previous = currentNode
}
}
currentNode.visited = true
unvisitedNodes.remove(currentNode)
if let newCurrent = unvisitedNodes.sorted(by: {
(nodeA, nodeB) -> Bool in
nodeA.distance < nodeB.distance
}).first {
currentNode = newCurrent
} else {
break
}
}
DijkstraGraph.printShortestPath(node: finishNode)
}
public static func printShortestPath(node:DijkstraNode<T>) {
if let previous = node.previous {
DijkstraGraph.printShortestPath(node: previous)
} else {
print("Shortest path:")
}
print("->\(node.value)", terminator:"")
}
}
实例
设现存一图如下:
先创建节点信息,接着边,最后图
let nodeA = DijkstraNode(value: "A", edges: [], visited: false)
let nodeB = DijkstraNode(value: "B", edges: [], visited: false)
let nodeC = DijkstraNode(value: "C", edges: [], visited: false)
let nodeD = DijkstraNode(value: "D", edges: [], visited: false)
let nodeE = DijkstraNode(value: "E", edges: [], visited: false)
let edgeAB = DijkstraEdge(weight: 3, from: nodeA, to: nodeB)
let edgeBA = DijkstraEdge(weight: 3, from: nodeB, to: nodeA)
let edgeAC = DijkstraEdge(weight: 1, from: nodeA, to: nodeC)
let edgeCA = DijkstraEdge(weight: 1, from: nodeC, to: nodeA)
let edgeBC = DijkstraEdge(weight: 1, from: nodeB, to: nodeC)
let edgeCB = DijkstraEdge(weight: 1, from: nodeC, to: nodeB)
let edgeBD = DijkstraEdge(weight: 2, from: nodeB, to: nodeD)
let edgeDB = DijkstraEdge(weight: 2, from: nodeD, to: nodeB)
let edgeDE = DijkstraEdge(weight: 1, from: nodeD, to: nodeE)
let edgeED = DijkstraEdge(weight: 1, from: nodeE, to: nodeD)
let edgeCE = DijkstraEdge(weight: 8, from: nodeC, to: nodeE)
let edgeEC = DijkstraEdge(weight: 8, from: nodeE, to: nodeC)
let graph = DijkstraGraph(nodes: [nodeA,nodeB,nodeC,nodeD,nodeE])
结果
Shortest path:
->A->C->B->D->E