swift中的优先队列

Posted

技术标签:

【中文标题】swift中的优先队列【英文标题】:Priority Queue in swift 【发布时间】:2014-07-01 16:40:14 【问题描述】:

我正在尝试实现 Dijkstra 算法的一个版本,以找到公共汽车从头到尾的最短路线。不幸的是,我似乎找不到 swift 提供一种优先级队列的库或其他方式,所以看来我必须自己编写代码。

话虽如此,任何人都可以为我指出正确的方向吗?

目前我的想法如下:

编写一个保存优先级数组的类。在这个类中将有一个方法接收一个值,将其添加到优先级数组中,然后根据优先级(在本例中为距离)对其进行排序。还有一个 get 函数,它从数组中返回最高优先级的项目。

我想知道我对优先级队列的理解是否接近或仍然遥遥无期。

谢谢。

编辑:

到目前为止,这是我的代码。似乎太短太粗暴了……我一定是在概念上遗漏了一些东西。

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)

【问题讨论】:

大致正确。该方法将值和优先级键作为参数。它将根据优先级键找到内部数据结构中保存对的位置以放置它。现在考虑如何设置该数据结构。您需要一个易于在中间添加、易于从中删除且易于进入开头的数据结构。如果您能找到将配对放在哪里开始(它会自行排序),则不必对任何内容进行排序。 编写一些代码并发布它以获得更多有用的反馈。这里和在线也有大量资源,其中包含实施细节。 Dijkstra's algorithm with priority queue 的可能重复项 谢谢@Al.Sal,我会尽快发布一些代码。我对我现在需要做什么有了更好的了解。 @kuast,我看到了这个问题。我的不同,因为如果有人对在哪里看有一些建议,它会迅速具体化。该问题还包括诸如更新周围节点等我没有的问题。在尝试从 OP 的角度看待问题之前,不要这么快对问题做出负面判断。 【参考方案1】:

您可能有兴趣查看我编写的两个开源项目。第一个是SwiftPriorityQueue:https://github.com/davecom/SwiftPriorityQueue

您对优先级队列的实现在 O(n lg n) 上进行排序。大多数优先级队列的实现,包括 SwiftPriorityQueue,都使用二进制堆作为后备存储。它们具有在 O(lg n) 中运行的推送操作和在 O(lg n) 中运行的弹出操作。因此,您的怀疑是正确的 - 您当前的实现不太可能非常高效(尽管 pop 在技术上更快)。

第二个是SwiftGraph:https://github.com/davecom/SwiftGraph

SwiftGraph 包含 Dijkstra 算法的实现。

令我惊讶的是,这两个项目都不太容易找到,因为它们已经推出一年多了,并且相当受欢迎,但根据去年对这个问题的当前答案,我似乎需要努力提高可发现性。

【讨论】:

【参考方案2】:

您应该使用堆排序作为优先级。我认为这是最优的!在操场上试试吧!

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)

【讨论】:

【参考方案3】:

查看“堆排序”的代码。 Heapsort 创建一个“堆”,它基本上是一个优先级队列,首先具有最大元素,然后它反复弹出 heap = 优先级队列的最大元素,将其移动到数组的末尾,并将先前的最后一个数组元素添加到优先队列。

在优先级队列中插入和删除项目必须是 O (log n) 操作。这就是优先级队列的全部意义所在。在将元素添加到优先级队列时调用“排序”绝对是荒谬的,并且会完全扼杀你的表现。

【讨论】:

以上是关于swift中的优先队列的主要内容,如果未能解决你的问题,请参考以下文章

数据结构——优先队列

优先队列和单调队列一样吗?

数据结构:优先队列-最大最小优先

优先级队列(Priority Queue)

优先队列和堆

优先队列和堆