棧(Stack)
棧(stack)是限制對(duì)元素的插入(push)和刪除(pop)只能在一個(gè)位置上進(jìn)行的表,該位置是表的末端,叫做棧的棧頂(top)。
進(jìn)棧和出棧
基于棧結(jié)構(gòu)的特點(diǎn),在實(shí)際應(yīng)用中,通常只會(huì)對(duì)棧執(zhí)行以下兩種操作:
- 向棧中添加元素,此過(guò)程被稱為
"進(jìn)棧"(入?;驂簵#?;- 從棧中提取出指定元素,此過(guò)程被稱為
"出棧"(或彈棧);
棧的實(shí)現(xiàn)
棧是一種 "特殊" 的線性存儲(chǔ)結(jié)構(gòu),因此棧的具體實(shí)現(xiàn)有以下兩種方式:
- 順序棧:采用順序存儲(chǔ)結(jié)構(gòu)可以模擬棧存儲(chǔ)數(shù)據(jù)的特點(diǎn),從而實(shí)現(xiàn)棧存儲(chǔ)結(jié)構(gòu);
- 鏈棧:采用鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)實(shí)現(xiàn)棧結(jié)構(gòu);
1. 數(shù)組實(shí)現(xiàn)
public struct Stack<T> {
fileprivate var array = [T]()
public var isEmpty: Bool {
return array.isEmpty
}
public var count: Int {
return array.count
}
public mutating func push(_ element: T) {
array.append(element)
}
public mutating func pop() -> T? {
return array.popLast()
}
public var top: T? {
return array.last
}
}
注意到,壓棧操作是將新元素壓入數(shù)組的尾部,而不是頭部。在數(shù)組的頭部插入元素是一個(gè)很耗時(shí)的操作,它的時(shí)間復(fù)雜度為 O(n),因?yàn)樾枰獙F(xiàn)有元素往后移位為新元素騰出空間。而在尾部插入元素的時(shí)間復(fù)雜度為 O(1);無(wú)論數(shù)組有多少元素,這個(gè)操作所消耗的時(shí)間都是一個(gè)常量。
2. 鏈表實(shí)現(xiàn)
這里我們使用單鏈表來(lái)實(shí)現(xiàn),定義一個(gè)first指針指向棧頂,棧的鏈表實(shí)現(xiàn)實(shí)際上是簡(jiǎn)化了單鏈表實(shí)現(xiàn),具體實(shí)現(xiàn)看以下代碼。
/// 鏈表節(jié)點(diǎn)類
public class ListNode<T> {
var value: T // 值
var next: ListNode<T>? = nil // 下一個(gè)節(jié)點(diǎn)
weak var previous: ListNode<T>? = nil
init(value: T) {
self.value = value
}
}
public class StackList<T> {
public var count: Int = 0
public var first: ListNode<T>?
public var isEmpty: Bool {
return count == 0
}
public func push(_ element: T) {
let oldNode = first
first = ListNode(value: element)
first?.next = oldNode
count += 1
}
public func pop() -> T? {
let value = first?.value
first = first?.next
count -= 1
return value
}
}
隊(duì)列(queue)
wiki: 隊(duì)列,又稱為佇列(queue),是先進(jìn)先出(FIFO, First-In-First-Out)的線性表。在具體應(yīng)用中通常用鏈表或者數(shù)組來(lái)實(shí)現(xiàn)。隊(duì)列只允許在后端(稱為rear)進(jìn)行插入操作,在前端(稱為front)進(jìn)行刪除操作。隊(duì)列的操作方式和堆棧類似,唯一的區(qū)別在于隊(duì)列只允許新數(shù)據(jù)在后端進(jìn)行添加。
多種隊(duì)列
隊(duì)列一般分為普通的數(shù)組隊(duì)列,鏈表隊(duì)列和循環(huán)隊(duì)列。
鏈表隊(duì)列:長(zhǎng)度一般是無(wú)限的,一般不存在溢出的可能性,用完就銷毀,不會(huì)浪費(fèi)內(nèi)存空間。
普通的數(shù)組隊(duì)列:長(zhǎng)度一般是有限的,即數(shù)組長(zhǎng)度。由于元素出隊(duì)后其位置的內(nèi)存空間并不會(huì)釋放,因此會(huì)浪費(fèi)大量的內(nèi)存空間。

循環(huán)隊(duì)列:特殊的數(shù)組隊(duì)列,由于普通的數(shù)組的隊(duì)列會(huì)浪費(fèi)大量的內(nèi)存空間,因此出現(xiàn)了循環(huán)隊(duì)列。當(dāng)循環(huán)隊(duì)列的隊(duì)尾指針到達(dá)數(shù)組末尾后,會(huì)重新回到數(shù)組起始位置,實(shí)現(xiàn)了對(duì)內(nèi)存的重復(fù)利用。

隊(duì)列的實(shí)現(xiàn)
1. 數(shù)組隊(duì)列
public struct Queue<T> {
fileprivate var array = [T]()
public var isEmpty: Bool {
return array.isEmpty
}
public var count: Int {
return array.count
}
public mutating func enqueue(_ element: T) {
array.append(element)
}
public mutating func dequeue() -> T? {
if isEmpty {
return nil
} else {
return array.removeFirst()
}
}
public var front: T? {
return array.first
}
}
2. 鏈表隊(duì)列
/// 鏈表節(jié)點(diǎn)類
public class ListNode<T> {
var value: T? // 值
var next: ListNode<T>? = nil // 下一個(gè)節(jié)點(diǎn)
weak var previous: ListNode<T>? = nil
init(value: T?) {
self.value = value
}
}
public class QueueByLinkList<T> {
public var count: Int = 0
public var first: ListNode<T>?
public var last: ListNode<T>?
public var isEmpty: Bool {
return count == 0
}
//初始化隊(duì)列
init() {
first = ListNode(value: nil)
last = first
count = 0
}
//入隊(duì)
public func enqueue(_ element: T) {
if isEmpty {
last?.value = element
count += 1
return
}
let oldNode = last
last = ListNode(value: element)
oldNode?.next = last
count += 1
}
//出隊(duì)
public func dequeue(_ element: T) -> T? {
if isEmpty {
print("***隊(duì)列為空***")
return nil
}
let value = first?.value
first = first?.next
count -= 1
return value
}
}
3. 循環(huán)隊(duì)列
public struct CycleQueue<T> {
fileprivate var queue = [T]()
fileprivate var queue_Capacity: Int = 0
var count: Int {
return queue.count
}
// 構(gòu)造函數(shù)創(chuàng)建出一個(gè)隊(duì)列數(shù)據(jù)模型來(lái)
init(queue_Capacity: Int) {
self.queue_Capacity = queue_Capacity
self.clearQueue()
}
/// 清空隊(duì)列
public mutating func clearQueue() {
queue.removeAll()
}
/// 判斷隊(duì)列是否已經(jīng)滿了
public func queueFull() -> Bool {
return queue_Capacity == count
}
var isEmpty: Bool {
return queue.isEmpty
}
/// 往隊(duì)列中添加一個(gè)元素
public mutating func enQueue(_ element : T) -> Bool {
if queueFull() {
print("隊(duì)列已滿")
return false
} else {
queue.append(element)
return true
}
}
/// 從隊(duì)列中取出來(lái)一個(gè)元素 如果隊(duì)列為空 那么 取出來(lái)的為 nil
public mutating func deQueue() -> T? {
if isEmpty {
return nil
} else {
let element = queue.removeFirst()
return element
}
}
/// 遍歷隊(duì)列
public func queueTraverse() {
if isEmpty {
print("隊(duì)列為空")
} else {
queue.forEach { (element) in
print("element: \(element)")
}
}
}
}
參考文章
淺談棧和隊(duì)列