這裏使用數組來存儲棧的數據。不足之處在於本例中的Stack能夠無限擴容,更好的是初始化時候指定一個最大容量,防止不斷擴容申請內存致使內存不夠的問題。這裏的線程安全使用一個串行隊列來保證,實際上也能夠經過加鎖或者信號量甚至自旋鎖來解決。node
struct Stack<Element> { private var items: [Element] private var queue = DispatchQueue(label: "StackOperationQueue") public init(capacity: Int = 10) { items = [Element]() items.reserveCapacity(capacity) } mutating public func push(item: Element) { queue.sync { items.append(item) } } mutating public func pop() -> Element? { var item: Element? queue.sync { item = items.removeLast() } return item } }
// 存儲數據的雙向鏈表節點 class DoubleLinkNode<Element> { var previous: DoubleLinkNode? var next: DoubleLinkNode? let val: Element? init(val: Element?) { self.val = val } //聲明==運算符,便於判斷兩個節點是否相等 static func ==(left: DoubleLinkNode<Element>, right: DoubleLinkNode<Element>) -> Bool { //最準確的作法是判斷內存地址是否相同 let leftPointValue = Unmanaged<AnyObject>.passUnretained(left).toOpaque() let rightPointValue = Unmanaged<AnyObject>.passUnretained(right).toOpaque() return leftPointValue == rightPointValue } } /* 1.使用雙向鏈表實現隊列結構,聲明空的head/last哨兵節點簡化雙向鏈表操做; 2.使用串行隊列保證線程安全,實際上也能夠經過加鎖的方式實現線程安全; 3.對於生產者-消費者模型,這裏可使用semaphore來實現,當隊列爲空的時候,讓線程休眠,當有元素入隊的時候喚醒一個線程繼續執行任務。 */ struct Queue<Element> { //聲明串行隊列,將操做放在串行隊列中,保證線程安全 private var queue = DispatchQueue(label: "QueueOperationQueue") let firstNode: DoubleLinkNode<Element> let lastNode: DoubleLinkNode<Element> public init(capacity: Int = 20) { firstNode = DoubleLinkNode(val: nil) lastNode = DoubleLinkNode(val: nil) firstNode.next = lastNode lastNode.previous = firstNode } /// 入隊操做 mutating public func enqueue(item: Element) { queue.sync { let node = DoubleLinkNode<Element>(val: item) let tmp = firstNode.next firstNode.next = node node.previous = firstNode node.next = tmp tmp?.previous = node } } /// 出隊操做 mutating public func dequeue() -> Element? { guard let previous = lastNode.previous, !(firstNode == previous) else { return nil } var node: DoubleLinkNode<Element>? = nil queue.sync { node = lastNode.previous node?.next = nil node?.previous = nil let tmp = node?.previous lastNode.previous = tmp tmp?.next = lastNode } return node?.val } }