I'm trying to implement a version of Dijkstra Algorithm to find the shortest route for a bus to take from start to end. Unfortunately, I cannot seem to find a library or other way that swift provides a type of priority queue so it seems I will have to code my own.
This being said, can anyone point me in the right direction to do this?
Currently my thinking is as follows:
Write a class which will hold the priority array. In this class there will be a method which receives a value, adds it to the priority array and then sorts it according to priority (In this case, distance). There will also be a get function which returns the highest priority item from the array.
I would like to know if I'm close or still way off in my understanding of a priority queue.
Thank you.
EDIT :
This is my code so far. Seems too short and brutal... I must be missing something in terms of the concept.
var priorityQueue = Dictionary<String, Int>()
var firstElement: String = ""
func push(name: String, distance: Int)
{
priorityQueue[name] = distance
var myArr = Array(priorityQueue.keys)
var sortedKeys = sort(myArr) {
var obj1 = self.priorityQueue[$0] // get obj associated w/ key 1
var obj2 = self.priorityQueue[$1] // get obj associated w/ key 2
return obj1 > obj2
}
firstElement = myArr[0]
var tempPriorityQueue = Dictionary<String, Int>()
for val in myArr
{
tempPriorityQueue[val] = priorityQueue[val]
}
priorityQueue = tempPriorityQueue
}
func pop() -> String
{
priorityQueue.removeValueForKey(firstElement)
}
You may be interested in looking at two open source projects that I've authored. The first is SwiftPriorityQueue: https://github.com/davecom/SwiftPriorityQueue
Your implementation of a priority queue sorts on push which is O(n lg n). Most implementations of a priority queue, including SwiftPriorityQueue, use a binary heap as the backing store. They have push operations that operate in O(lg n) and pops that operate in O(lg n) as well. Therefore your suspicions are right - your current implementation is unlikely to be very performant (although pops are technically faster).
The second is SwiftGraph: https://github.com/davecom/SwiftGraph
SwiftGraph includes an implementation of Dijkstra's Algorithm.
I'm surprised neither of these projects was easier to find since they have been out for over a year and moderately popular, but based on current answers to this question in the last year, it seems I need to work on discoverability.
You should use heap sort for the priority. I think this is optimal! Try it out in playground!
import Foundation
typealias PriorityDefinition<P> = (_ p1: P, _ p2: P) -> (Bool)
class PriorityQueue<E, P: Hashable> {
var priDef: PriorityDefinition<P>!
var elemments = [P: [E]]()
var priority = [P]()
init(_ priDef: @escaping PriorityDefinition<P>) {
self.priDef = priDef
}
func enqueue(_ element: E!, _ priorityValue: P!) {
if let _ = elemments[priorityValue] {
elemments[priorityValue]!.append(element)
} else {
elemments[priorityValue] = [element]
}
if !priority.contains(priorityValue) {
priority.append(priorityValue)
let lastIndex = priority.count - 1
siftUp(0, lastIndex, lastIndex)
}
}
func dequeue() -> E? {
var result: E? = nil
if priority.count > 0 {
var p = priority.first!
if elemments[p]!.count == 1 {
if priority.count > 1 {
let _temp = priority[0]
priority[0] = priority[priority.count - 1]
priority[priority.count - 1] = _temp
p = priority.last!
siftDown(0, priority.count - 2)
}
result = elemments[p]!.removeFirst()
elemments[p] = nil
priority.remove(at: priority.index(of: p)!)
} else {
result = elemments[p]!.removeFirst()
}
}
return result
}
func siftDown(_ start: Int, _ end: Int) {
let iLeftChild = 2 * start + 1
if iLeftChild <= end {
var largestChild = priDef(priority[iLeftChild], priority[start]) ? iLeftChild : start
let iRightChild = 2 * start + 2
if iRightChild <= end {
if priDef(priority[iRightChild], priority[iLeftChild]) {
largestChild = iRightChild
}
}
if largestChild == start {
return
} else {
let _temp = priority[start]
priority[start] = priority[largestChild]
priority[largestChild] = _temp
siftDown(largestChild, end)
}
}
}
func siftUp(_ start: Int, _ end: Int, _ nodeIndex: Int) {
let parent = (nodeIndex - 1) / 2
if parent >= start {
if priDef(priority[nodeIndex], priority[parent]) {
let _temp = priority[nodeIndex]
priority[nodeIndex] = priority[parent]
priority[parent] = _temp
siftUp(start, end, parent)
} else {
return
}
}
}
func isEmpty() -> Bool {
return priority.count == 0
}
}
let Q = PriorityQueue<Int, Int> { (p1: Int, p2: Int) -> (Bool) in
return p1 > p2
}
let n = 999
for i in 0...n - 1 {
let start = NSDate().timeIntervalSince1970
Q.enqueue(i, i)
let end = NSDate().timeIntervalSince1970
print(end - start)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With