本篇文章主要内容:
- 栈与队列的基本概念
- 栈与队列的基本结构
- 栈与队列的互相实现
栈
概念
-
栈(stack)是限定仅在表尾进行插入和删除操作的线性表。
-
我们把允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又称为后进先出(LastIn First Out)的线性表,简称LIFO结构。
结构
对栈来说,一般我们只需要关注:push, pop, isEmpty, peek, size 等操作。
顺序存储结构:
class Stack {
// 是否为空
var isEmpty: Bool {
return stack.isEmpty
}
// 栈的大小
var size: Int {
return stack.count
}
// 栈顶元素
var peek: Int? {
return stack.last
}
// 入栈
func push(_ value: Int) {
stack.append(value)
}
// 出栈
func pop() -> Int? {
return stack.popLast()
}
private var stack: [Int] = []
}
链式存储结构:
class Node {
var value: Int?
var next: Node?
init(_ value: Int?) {
self.value = value
self.next = nil
}
}
class Stack_Link {
private var head: Node? // 指向栈顶元素的指针
var isEmpty: Bool {
return head == nil
}
var size: Int {
get {
var count = 0
var node = head?.next
while node != nil {
count += 1
node = node?.next
}
return count
}
}
var peek: Node? {
return head?.next
}
func push(_ value: Int) {
if head == nil {
head = Node(nil)
}
let newNode = Node(value)
let lastTop = head?.next
newNode.next = lastTop
head?.next = newNode
}
func pop() -> Node? {
let top = head?.next
head?.next = top?.next
return top
}
}
队列
概念
-
队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
-
队列是一种先进先出(First In First Out)的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。
结构
对队列来说,一般我们只需要关注:enterQueue, outQueue, isEmpty, peek, size 等操作。
队列顺序存储结构:
class Queue {
// 是否为空
var isEmpty: Bool {
return queue.isEmpty
}
// 队列的大小
var size: Int {
return queue.count
}
// 队头元素
var peek: Int? {
return queue.last
}
// 入队操作
func enterQueue(_ value: Int) {
queue.append(value)
}
// 出队操作
func outQueue() -> Int? {
if let element = queue.first {
queue.removeFirst()
return element
}
return nil
}
private var queue: [Int] = []
}
队列链式存储结构:
class Node {
var value: Int?
var next: Node?
init(_ value: Int?) {
self.value = value
self.next = nil
}
}
class Queue_Link {
private var head: Node? // 指向队头
private var tail: Node? // 指向队尾
var isEmpty: Bool {
return head == nil && tail == nil
}
var size: Int {
get {
var count = 0
var node = head?.next
while node != nil {
count += 1
node = node?.next
}
return count
}
}
var peek: Node? {
return head?.next
}
func enterQueue(_ value: Int) {
let newNode = Node(value)
if head == nil {
head = Node(nil)
tail = Node(nil)
head?.next = newNode
tail?.next = newNode
} else {
let lastTail = tail?.next
lastTail?.next = newNode
tail?.next = newNode
}
}
func outQueue() -> Node? {
let top = head?.next
head?.next = top?.next
return top
}
}
互相实现
用栈实现队列
思路: 因为栈的先进后出特性,需要完成先进先出的特点。我们需要用到两个栈,一个 enterStack,专门负责入队的操作,另一个 outStack,负责协助出队。当入队时,我们将新元素 push 到 enterStack 中,出队时分为两个步骤,先将 enterQueue 的元素 pop 出来,并将 pop 的元素加入到 outStack 中,此时 outStack 的栈顶元素就是最先入队的元素。
代码:
class ImplementQueueByStack {
private var enterStack = Stack()
private var outStack = Stack()
var isEmpty: Bool {
return enterStack.isEmpty && outStack.isEmpty
}
var size: Int {
return enterStack.size + outStack.size
}
var peek: Int? {
get {
tab()
return outStack.peek
}
}
func enterQueue(_ value: Int) {
enterStack.push(value)
}
func outQueue() -> Int? {
tab()
return outStack.pop()
}
// 将 enter 中的值,加入到 out 中
private func tab() {
if outStack.isEmpty {
while !enterStack.isEmpty {
outStack.push(enterStack.pop()!)
}
}
}
}
用队列实现栈
思路: 根据栈实现队列的思路,这里我们也用两个队列来实现栈。一个 enterQueue,负责入栈,另一个 outQueue 负责协助出栈。入栈时,将新的元素加入到 enterQueue中,出栈时,也分为两个步骤,先将 enterQueue 中的元素出队至最后一个元素,并将所有出队的元素加入到 outQueue 中,此时,enterQueue 中剩下的元素即是我们需要出栈的元素。
代码:
class ImplementStackByQueue {
private var enterQueue = Queue()
private var tempQueue = Queue()
var isEmpty: Bool {
return enterQueue.isEmpty && tempQueue.isEmpty
}
var size: Int {
return enterQueue.size
}
var peek: Int? {
get {
tab()
let peekElement = enterQueue.peek
tempQueue.enterQueue(enterQueue.outQueue()!)
swap()
return peekElement
}
}
func push(_ value: Int) {
enterQueue.enterQueue(value)
}
func pop() -> Int? {
tab()
let popElement = enterQueue.outQueue()
swap()
return popElement
}
private func tab() {
while enterQueue.size != 1 {
tempQueue.enterQueue(enterQueue.outQueue()!)
}
}
private func swap() {
(enterQueue, tempQueue) = (tempQueue, enterQueue)
}
}