2015-04-10 4 views
4

Я пытаюсь реализовать тип коллекции Queue на платформе Swift. У меня возникли проблемы с функциями просмотра, опроса и предложения. Когда я пытаюсь использовать эти функции в своем коде, он терпит неудачу. У вас есть какой-нибудь совет или настоящий алгоритм?Реализация очереди в языке Swift

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 
    } 
} 
+1

Я думаю, вы должны быть более конкретными, когда вы говорите, у вас есть * некоторые проблемы * и * он терпит неудачу *. Неожиданные результаты, исключения времени выполнения, ... – Antonio

+0

@ Антонио вы правы. основная проблема заключается в том, что я считаю. Особенно популярность и предложение algoritm дают ноль, и приложение терпит неудачу. Все они являются общими исключениями, я не мог понять это – gokhangokce

+1

Я предлагаю вам поставить некоторые точки останова и потратить некоторое время на отладку - и я рекомендую написать несколько тестов, начиная с очень простых тестов (таких как длина тестирования для пустой очереди) и постепенно увеличивая их сложность. – Antonio

ответ

15

Помимо ошибок, есть несколько вещей, о вашей реализации, которые вы, вероятно, хотите изменить, чтобы сделать его более Swift как. Во-первых, похоже, что вы копируете имена Java, такие как и offer - эти имена (IMHO) немного странны и отчасти связаны с необходимостью иметь две функции, версию для исключения и версию без исключения. Поскольку Swift не имеет исключений, вы, вероятно, можете просто назвать их, используя обычные имена, используемые другими коллекциями Swift, например append.

Другая проблема заключается в том, что ваша реализация включает перемещение очереди в очередь. Лучше делать такой обход вне коллекции, чем смешивать их. Быстрые коллекции делают это с индексами.

Вот возможная реализация очереди в стиле Swift. Во-первых, определение узла и базы очереди:

// 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() { } 
} 

Затем продлите с append и dequeue метод:

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 
     } 
    } 
} 

На данный момент, вы почти закончили, если все, что вам нужно сделать, это добавить и удалить. Для добавления обхода, необходимо сначала создать тип индекса, который является просто оболочкой от типа узла:

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 
} 

Затем использовать этот индекс, чтобы соответствовать 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) 
    } 
} 

С в соответствии с типом коллекции, вы получаете весь груз вещи бесплатно:

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] 

Наконец, есть еще 3 протоколов, которые хорошо соответствуют: ExtensibleCollectionType, Printable в d ArrayLiteralConvertible:

// 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)) + "]" 
    } 
} 

Это значит, теперь вы можете создавать очереди, как легко массивы или наборы:

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

большое вам спасибо. это так полезно. Я просто пытаюсь преобразовать один из моих сложных академических проектов Android в ios, и я застрял здесь. поэтому я попытаюсь реализовать возможности просмотра, опроса и предложения. Еще раз спасибо – gokhangokce

+0

Я пробовал ваш код, я получаю segmentation fault on for loop. Вы мне посоветовали? Etc: для x в q {} это дает ошибку сегментации – gokhangokce

+0

Привет, скорость Airspeed Velocity. В настоящее время я использую эту реализацию в нашем проекте Swift 2.3, однако при переходе на Swift 3.0 ForwardIndexType был переименован в Comparable. Не могли бы вы добавить версию Swift 3.0 для этой очереди? – chlkdst

3

Есть много маленьких вопросов, касающихся внутренней согласованности модели:

  1. Когда вы впервые создаете экземпляр нового Queue, вы инициализируете head, tail и current до трех разных объектов Node (хотя ничего еще не поставлено в очередь!). Это не имеет смысла. Лично я был бы склонен сделать эти три свойства необязательными и оставить их как nil, пока вы не начнете входить в очередь.

    Кстати, когда вы начинаете использовать опции для этих свойств, многие другие методы упрощаются.

  2. Похоже, вы пытаетесь реализовать двусвязный список. Таким образом, когда вы деактируете, вам нужно не только обновлять свойства Queue, но также необходимо обновить указатель next для следующего элемента, который будет удален (потому что он все равно укажет на тот объект, который вы уже выбрали). Вы не хотите, чтобы связанный список поддерживал ссылки на объекты, которые были удалены и должны быть удалены.

  3. Когда вы удаляете последний элемент, вам действительно нужно освободить head и tail ссылок.

  4. Вы реализуете двусвязный список, независимо от модели владения объектами. Таким образом, как только у вас есть более одного элемента в вашем списке, у вас есть сильный ссылочный цикл между узлами, и если он не исправлен, это будет протекать, если в очереди остались объекты, когда сама очередь освобождается. Попробуйте сделать одну из ссылок weak или unowned.

  5. Я предлагаю сохранить это просто (просто в очереди и dequeue). Концепция poll и offer может иметь смысл в терминах произвольного связанного списка, но не в контексте очереди. Реализации poll и offer также неверны (например, poll вызывает deQueue, который удаляет хвост, но возвращаемый объект является head!), Но я полагаю, вы просто полностью удалили бы эти функции. Аналогично, я не понимаю намерения current в контексте очереди.

  6. Я предлагаю вам сделать Queue и Node соответствовать Printable. Это упростит процесс отладки.

+0

Вы полностью верны. Спасибо за ваш совет. – gokhangokce

2

Ниже приведен код игровой площадки, состоящей из очереди, реализованной с массивом, и очереди, реализованной с узлами. Существуют существенные различия в производительности между ними, но если вы собираетесь выполнять итерацию через очередь, вы можете использовать ее с массивом.

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))") 
0

Swift 4 Simple Queue для любого типа; строка, INT, массив и т.д.

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) 
     } 
    } 

пример со строками:

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 
более

информация здесь: // https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html

Смежные вопросы