数据结构_两种方法解决Queue的复杂度问题

538 阅读1分钟

一、问题

先来看入队和出队的两个方法:

public mutating func enqueue(_ element: T) {
    queueArr.append(element)
}
    
public mutating func dequeue() -> T? {
    return isEmpty ? nil : queueArr.removeFirst()
}

入队的时候的时候,复杂度为O(1),然而出队的时候复杂度变成了O(n)。出队的方法dequeue()使用的数组里removeFrist方法,而这个方法的说明文档描述了它的复杂度:

原因:

  • 删除索引为0的元素,也就是第一个元素时,会把之后的所有元素重新从索引0开始赋值,因此复杂度取决于这些元素的数量,也就是O(n)。

二、解决

使用双端队列Deque

双端队列Deque需要实现的方法:

Deque

 · func enqueue(E)
 · func dequeue() -> E  (重写)
 · var front -> E
 · var count -> int
 · var isEmpty -> Bool

双端队列Deque的swift代码实现:


public struct Queue<T> {
  fileprivate var array = [T?]()
  fileprivate var head = 0
  
  public var isEmpty: Bool {
    return count == 0
  }

  public var count: Int {
    return array.count - head
  }
  
  public mutating func enqueue(_ element: T) {
    array.append(element)
  }
  
  public mutating func dequeue() -> T? {
    guard head < array.count, let element = array[head] else { return nil }

    array[head] = nil
    head += 1

    let percentage = Double(head)/Double(array.count)
    if array.count > 50 && percentage > 0.25 {
      array.removeFirst(head)
      head = 0
    }
    
    return element
  }
  
  public var front: T? {
    if isEmpty {
      return nil
    } else {
      return array[head]
    }
  }
}


使用基于链表实现的队列

基于链表实现的队列需要实现的方法:

Queue Based on LinkedList

 · func enqueue(E)
 · func dequeue() -> E  (重写)
 · func front() -> E
 · var count -> int
 · var isEmpty -> Bool

基于链表实现的队列的swift代码实现:

public struct Queue<T> {

  fileprivate var list = LinkedList<T>()

  public var isEmpty: Bool {
    return list.isEmpty
  }
  
  public var count: Int {
    return list.count
  }
  
  public mutating func enqueue(_ element: T) {
    list.append(element)
  }

  public mutating func dequeue() -> T? {
    guard !list.isEmpty, let element = list.first else { return nil }

    list.remove(element)

    return element.value
  }

  public func front() -> T? {
    return list.first?.value
  }
}

总结

这些具体的实现其目的都是把出队dequeue()这个方法从O(n)的复杂度变成了O(1)。