【问题标题】:Priority Queue in swiftswift中的优先队列
【发布时间】: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)
}

【问题讨论】:

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

标签: algorithm swift priority-queue


【解决方案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) 操作。这就是优先级队列的全部意义所在。在将元素添加到优先级队列时调用“排序”绝对是荒谬的,并且会完全扼杀你的表现。

      【讨论】:

        猜你喜欢
        • 2011-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-11
        • 1970-01-01
        • 1970-01-01
        • 2010-12-28
        • 2012-03-28
        相关资源
        最近更新 更多