简体   繁体   English

Swift 语言中的队列实现

[英]Queue implementation in Swift language

I m trying to implement Queue collection type in Swift platform.我正在尝试在 Swift 平台中实现 Queue 集合类型。 I have got some problems about peek, poll and offer functions.我在查看、投票和提供功能方面遇到了一些问题。 When I try to use these functions in my code, it fails.当我尝试在我的代码中使用这些函数时,它失败了。 Do you have any advice or true algorithm for that?你有什么建议或真正的算法吗?

import Foundation


class Node<T> {
    var value: T? = nil
    var next: Node<T>? = nil
    var prev: Node<T>? = nil

    init() {
    }

    init(value: T) {
        self.value = value
    }
}

class Queue<T> {

var count: Int = 0

var head: Node<T> = Node<T>()

var tail: Node<T> = Node<T>()

var currentNode : Node<T> = Node<T>()

    init() {
    }

    func isEmpty() -> Bool {
        return self.count == 0
    }

    func next(index:Int) -> T? {

        if isEmpty() {
            return nil
        } else if self.count == 1 {
            var temp: Node<T> = currentNode
            return temp.value
        } else if index == self.count{
            return currentNode.value

        }else {
            var temp: Node<T> = currentNode
            currentNode = currentNode.next!
            return temp.value
        }

    }

    func setCurrentNode(){
        currentNode = head
    }

    func enQueue(key: T) {
        var node = Node<T>(value: key)
        if self.isEmpty() {
            self.head = node
            self.tail = node
        } else {
            node.next = self.head
            self.head.prev = node
            self.head = node
        }

        self.count++
    }

    func deQueue() -> T? {
        if self.isEmpty() {
            return nil
        } else if self.count == 1 {
            var temp: Node<T> = self.tail
            self.count--
            return temp.value
        } else {
            var temp: Node<T> = self.tail
            self.tail = self.tail.prev!
            self.count--
            return temp.value
        }
    }



    //retrieve the top most item
    func peek() -> T? {

        if isEmpty() {
            return nil
        }

        return head.value!
    }

    func poll() -> T? {

        if isEmpty() {
            return nil
        }else{
            var temp:T = head.value!
            deQueue()
            return temp
        }

    }

    func offer(var key:T)->Bool{
        var status:Bool = false;

        self.enQueue(key)
        status = true


        return status
    }
}

Aside from the bugs, there are a couple of things about your implementation that you probably want to change to make it more Swift-like.除了 bug 之外,您可能想要更改一些关于您的实现的事情,以使其更像 Swift。 One is it looks like you're replicating the Java names like poll and offer – these names are (IMHO) a little strange, and partly related to needing to have two functions, an exception-throwing version and a non-exception version.一个是看起来你正在复制像polloffer这样的 Java 名称——这些名称(恕我直言)有点奇怪,部分与需要有两个函数有关,一个异常抛出版本和一个非异常版本。 Since Swift doesn't have exceptions, you can probably just name them using the conventional names other Swift collections use, like append.由于 Swift 没有异常,您可能可以使用其他 Swift 集合使用的常规名称来命名它们,例如 append。

The other issue is that your implementation incorporates traversing the queue into the queue itself.另一个问题是您的实现将队列遍历到队列本身中。 It's better to do this kind of traversal outside the collection than mix the two.最好在集合外进行这种遍历,而不是将两者混合。 Swift collections do this with indexes. Swift 集合使用索引来做到这一点。

Here's a possible Swift-like queue implementation.这是一个可能的类似 Swift 的队列实现。 First, the node and base queue definition:一、节点和基队列定义:

// singly rather than doubly linked list implementation
// private, as users of Queue never use this directly
private final class QueueNode<T> {
    // note, not optional – every node has a value
    var value: T
    // but the last node doesn't have a next
    var next: QueueNode<T>? = nil

    init(value: T) { self.value = value }
}

// Ideally, Queue would be a struct with value semantics but 
// I'll leave that for now
public final class Queue<T> {
    // note, these are both optionals, to handle
    // an empty queue
    private var head: QueueNode<T>? = nil
    private var tail: QueueNode<T>? = nil

    public init() { }
}

Then, extend with an append and dequeue method:然后,使用appenddequeue方法扩展:

extension Queue {
    // append is the standard name in Swift for this operation
    public func append(newElement: T) {
        let oldTail = tail
        self.tail = QueueNode(value: newElement)
        if  head == nil { head = tail }
        else { oldTail?.next = self.tail }
    }

    public func dequeue() -> T? {
        if let head = self.head {
            self.head = head.next
            if head.next == nil { tail = nil }
            return head.value
        }
        else {
            return nil
        }
    }
}

At this point, you're almost done if all you want to do is add and remove.此时,如果您要做的只是添加和删除,那么您就快完成了。 To add traversal, first create an index type, which is a simple wrapper on the node type:要添加遍历,首先创建一个索引类型,它是对节点类型的简单包装:

public struct QueueIndex<T>: ForwardIndexType {
    private let node: QueueNode<T>?
    public func successor() -> QueueIndex<T> {
        return QueueIndex(node: node?.next)
    }
}

public func ==<T>(lhs: QueueIndex<T>, rhs: QueueIndex<T>) -> Bool {
    return lhs.node === rhs.node
}

Then, use this index to conform to MutableCollectionType :然后,使用此索引符合MutableCollectionType

extension Queue: MutableCollectionType {
    public typealias Index = QueueIndex<T>
    public var startIndex: Index { return Index(node: head) }
    public var endIndex: Index { return Index(node: nil) }

    public subscript(idx: Index) -> T {
        get {
            precondition(idx.node != nil, "Attempt to subscript out of bounds")
            return idx.node!.value
        }
        set(newValue) {
            precondition(idx.node != nil, "Attempt to subscript out of bounds")
            idx.node!.value = newValue
        }
    }

    typealias Generator = IndexingGenerator<Queue>
    public func generate() -> Generator {
        return Generator(self)
    }
}

From conforming to collection type, you get a whole load of stuff for free:从符合集合类型,你可以免费获得一大堆东西:

var q = Queue<String>()
q.append("one")
q.append("two")

for x in q {
    println(x)
}

isEmpty(q) // returns false
first(q)   // returns Optional("one")
count(q)   // returns 2
",".join(q)  // returns "one,two"
let x = find(q, "two")  // returns index of second entry
let counts = map(q) { count($0) }  // returns [3,3]

Finally, there's 3 more protocols that are good to conform to: ExtensibleCollectionType , Printable and ArrayLiteralConvertible :最后,还有 3 个更适合遵守的协议: ExtensibleCollectionTypePrintableArrayLiteralConvertible

// init() and append() requirements are already covered
extension Queue: ExtensibleCollectionType {
    public func reserveCapacity(n: Index.Distance) {
        // do nothing
    }

    public func extend<S : SequenceType where S.Generator.Element == T>
      (newElements: S) {
        for x in newElements {
            self.append(x)
        }
    }
}

extension Queue: ArrayLiteralConvertible {
    public convenience init(arrayLiteral elements: T...) {
        self.init()
        // conformance to ExtensibleCollectionType makes this easy
        self.extend(elements)
    }
}

extension Queue: Printable {
    // pretty easy given conformance to CollectionType
    public var description: String {
        return "[" + ", ".join(map(self,toString)) + "]"
    }
}

These mean you can now create queues as easily arrays or sets:这意味着您现在可以轻松地将队列创建为数组或集合:

var q: Queue = [1,2,3]
println(q)  // prints [1, 2, 3]

There are a lot of little issues regarding the internal consistency of your model:关于模型的内部一致性有很多小问题:

  1. When you first instantiate a new Queue , you are initializing head , tail and current to three different Node objects (even though nothing's been queued yet!).当您第一次实例化一个新的Queue ,您将headtailcurrent初始化为三个不同的Node对象(即使尚未排队!)。 That doesn't make sense.那没有意义。 Personally, I'd be inclined to make those three properties optional and leave them as nil until you start enqueuing stuff.就我个人而言,我倾向于将这三个属性设为可选并将它们保留为nil直到您开始排队。

    By the way, when you start using optionals for these properties, many of the other methods are simplified.顺便说一句,当您开始为这些属性使用可选项时,许多其他方法都得到了简化。

  2. It looks like you're trying to implement a doubly linked list.看起来您正在尝试实现双向链表。 So, when you dequeue, you need to not only update the Queue properties, but you also need to update the next pointer for the next item that will be dequeued (because it still will be pointing to that item you already dequeued).因此,当您出队时,您不仅需要更新Queue属性,还需要更新next一个将出队的项目的next指针(因为它仍将指向您已经出队的项目)。 You don't want your linked list maintaining references to objects that have been dequeued and should be removed.您不希望您的链表维护对已出列并应删除的对象的引用。

  3. When you dequeue the last item, you really should be clearing out head and tail references.当您出列最后一项时,您确实应该清除headtail引用。

  4. You're implementing a doubly linked list, without regard to the object ownership model.您正在实现一个双向链表,而不考虑对象所有权模型。 Thus, as soon as you have more than one item in your list, you've got a strong reference cycle between nodes and if not remedied, this will leak if there are still objects in the queue when the queue, itself, is deallocated.因此,一旦您的列表中有多个项目,您就会在节点之间获得一个强大的引用循环,如果不加以补救,如果队列本身被释放时队列中仍有对象,则会泄漏。 Consider making one of the references weak or unowned .考虑将其中一个引用unowned weakunowned

  5. I'd suggest keeping this simple (just enqueue and dequeue).我建议保持这个简单(只是入队和出队)。 The concept of poll and offer may make sense in terms of an arbitrary linked list, but not in the context of a queue. polloffer的概念在任意链表方面可能有意义,但在队列的上下文中可能没有意义。 The implementations of poll and offer are also incorrect (eg poll calls deQueue which removes the tail, but the object you return is the head !), but I presume you'd just remove these functions altogether. polloffer的实现也是不正确的(例如, poll调用deQueue删除了尾部,但您返回的对象是head !),但我认为您只是完全删除了这些函数。 Likewise, I do not understand the intent of current in the context of a queue.同样,我不理解current在队列上下文中的意图。

  6. I'd suggest you make Queue and Node conform to Printable .我建议你让QueueNode符合Printable It will simplify your debugging process.它将简化您的调试过程。

The following is code of a playground consisting of a queue implemented with an array and a queue implemented with nodes.下面是一个操场的代码,它由一个用数组实现的队列和一个用节点实现的队列组成。 There are substantial performance differences between the two but if you going to be iterating through a queue you might want to use one with an array.两者之间存在显着的性能差异,但如果您要遍历队列,您可能希望将一个与数组一起使用。

import UIKit // for NSDate() used in testing)

// QUEUE WITH ARRAY IMPLEMENTATION (For ease of adaptibility, slow enque, faster deque):

struct QueueArray<T> {
    private var items = [T]()

    mutating func enQueue(item: T) {
        items.append(item)
    }

    mutating func deQueue() -> T? {
        return items.removeFirst()
    }

    func isEmpty() -> Bool {
        return items.isEmpty
    }

    func peek() -> T? {
        return items.first
    }
}

// QUEUE WITH NODE IMPLEMENTATION (For performance, if all you need is a queue this is it):

class QNode<T> {
    var value: T
    var next: QNode?

    init(item:T) {
        value = item
    }
}

struct Queue<T> {
    private var top: QNode<T>!
    private var bottom: QNode<T>!

    init() {
        top = nil
        bottom = nil
    }

    mutating func enQueue(item: T) {

        let newNode:QNode<T> = QNode(item: item)

        if top == nil {
            top = newNode
            bottom = top
            return
        }

        bottom.next = newNode
        bottom = newNode
    }

    mutating func deQueue() -> T? {

        let topItem: T? = top?.value
        if topItem == nil {
            return nil
        }

        if let nextItem = top.next {
            top = nextItem
        } else {
            top = nil
            bottom = nil
        }

        return topItem
    }

    func isEmpty() -> Bool {

        return top == nil ? true : false
    }

    func peek() -> T? {
        return top?.value
    }
}



// QUEUE NODES TEST

let testAmount = 100

var queueNodes = Queue<Int>()

let queueNodesEnqueStart = NSDate()

for i in 0...testAmount {
    queueNodes.enQueue(i)
}

let queueNodesEnqueEnd = NSDate()

while !queueNodes.isEmpty() {
    queueNodes.deQueue()
}

let queueNodesDequeEnd = NSDate()

// QUEUE ARRAY TEST

var queueArray = QueueArray<Int>()

let queueArrayEnqueStart = NSDate()

for i in 0...testAmount {
    queueArray.enQueue(i)
}

let queueArrayEnqueEnd = NSDate()

while !queueArray.isEmpty() {
    queueArray.deQueue()
}

let queueArrayDequeEnd = NSDate()

// QUEUE NODES RESULT:

print("queueEnqueDuration: \(queueNodesEnqueEnd.timeIntervalSinceDate(queueNodesEnqueStart)), Deque: \(queueNodesDequeEnd.timeIntervalSinceDate(queueNodesEnqueEnd))")

// QUEUE ARRAY RESULT:

print("queueArrayEnqueDuration: \(queueArrayEnqueEnd.timeIntervalSinceDate(queueArrayEnqueStart)), Deque: \(queueArrayDequeEnd.timeIntervalSinceDate(queueArrayEnqueEnd))")

Swift 4 simple queue for any type;适用于任何类型的 Swift 4 简单队列; string, int, array, etc.字符串、整数、数组等。

struct Stack<Element>  {
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
    mutating func peek() -> Element {
        return items.last!
    }
    mutating func pushFirst(_ item: Element) {
        items.insert(item, at: 0)
    }
}

example with strings:字符串示例:

 let names = ["Bob", "Sam", "Sue", "Greg", "Brian", "Dave"]

 //create stack of string type
 var stackOfStrings = Stack<String>()

 //add to bottom of stack
 for stringName in names {
    stackOfStrings.push(stringName)
 }

 //print and remove from stack
 for stringName in names {
    print(stringName)
    stackOfStrings.pop(stringName)
 }

 //add to top of stack
 for stringName in names {
    stackOfStrings.pushFirst(stringName)
 }

 //look at item in stack without pop
 for stringName in names {
    //see what Top item is without remove
    let whatIsTopItem = stackOfStrings.peek(stringName)
    if whatIsTopItem == "Bob" {
      print("Best friend Bob is in town!")
    }
 }

 //stack size
 let stackCount = stackOfStrings.items.count

more info here:更多信息在这里:

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html

Queue with Array带数组的队列

struct Queue<T> { 
    private var list = [T]() 

    var isEmpty: Bool { return self.list.isEmpty } 
    var front: T? { return self.list.first } 

    mutating func enqueue(_ item: T) { 
        self.list.append(item) 
    } 

    mutating func dequeue() -> T? { 
        guard self.isEmpty == false else { return nil } 
        return self.list.removeFirst() 
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM