用栈实现队列 (Implement Queue using Stacks)
题目描述
使用两个栈实现一个队列。队列的操作包括 push(x)
、pop()
、peek()
和 empty()
。
示例:
plaintext
MyQueue queue = new MyQueue();
queue.push(1);
queue.push(2);
queue.peek(); // 返回 1
queue.pop(); // 返回 1
queue.empty(); // 返回 false
注意:
- 你只能使用标准的栈操作,即
push to top
、peek/pop from top
、size
和is empty
这些操作是合法的。 - 你所使用的语言也许不支持栈。你可以使用 list 或 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
- 假设所有操作都是有效的。例如,当队列为空时,不调用
pop
或peek
操作。
代码实现
swift
class MyQueue {
private var stack1: [Int]
private var stack2: [Int]
/** Initialize your data structure here. */
init() {
stack1 = [Int]()
stack2 = [Int]()
}
/** Push element x to the back of queue. */
func push(_ x: Int) {
stack1.append(x)
}
/** Removes the element from in front of queue and returns that element. */
func pop() -> Int {
if stack2.isEmpty {
while !stack1.isEmpty {
stack2.append(stack1.removeLast())
}
}
return stack2.removeLast()
}
/** Get the front element. */
func peek() -> Int {
if stack2.isEmpty {
while !stack1.isEmpty {
stack2.append(stack1.removeLast())
}
}
return stack2.last!
}
/** Returns whether the queue is empty. */
func empty() -> Bool {
return stack1.isEmpty && stack2.isEmpty
}
}
注意点
在 Swift 中,Array 的实例(或对象)方法 removeFirst()
和 removeLast()
除了执行本身的 remove 操作,还会 return 对应 removed 元素。
swift
// Removes and returns the first element of the collection.
@discardableResult
@inlinable public mutating func removeFirst() -> Element
// Removes and returns the last element of the collection.
@discardableResult
@inlinable public mutating func removeLast() -> Element
swift
// Error: Cannot use mutating member on immutable value of type '[Int]'
[1,2,3].removeFirst()
在 Swift 中,如果你试图在不可变数组上调用可变方法(例如 removeFirst()
),会导致错误。为了修复这个错误,你需要确保数组是可变的。下面是一些正确处理的方式:
使用可变数组
确保你的数组是用 var
声明的,这样你就可以对它进行修改。
swift
var array = [1, 2, 3]
array.removeFirst() // 现在不会报错
print(array) // 输出: [2, 3]
使用不可变数组并创建可变副本
如果你的数组必须是不可变的,你可以创建一个可变副本来进行修改。
swift
let immutableArray = [1, 2, 3]
var mutableArray = immutableArray
mutableArray.removeFirst()
print(mutableArray) // 输出: [2, 3]
完整示例
以下是如何在实际代码中使用可变数组的示例:
swift
func processArray() {
var array = [1, 2, 3]
array.removeFirst()
print(array) // 输出: [2, 3]
}
processArray()
通过确保数组是可变的,你可以成功调用诸如 removeFirst()
之类的可变方法,而不会遇到错误。
拓展 - Swift 中为什么没有原生支持的 Stack 和 Queue 数据结构 ?
Swift 中没有原生支持的 Stack 和 Queue 数据结构的原因主要有以下几个方面:
1. 泛用数据结构的灵活性
Swift 标准库提供了一些强大的泛用数据结构,例如 Array
和 Dictionary
,它们可以用来构建多种不同的数据结构。Array
本身就可以方便地用来实现 Stack 和 Queue,只需要添加一些扩展方法。例如:
swift
// 实现 Stack
struct Stack<T> {
private var elements: [T] = []
mutating func push(_ element: T) {
elements.append(element)
}
mutating func pop() -> T? {
return elements.popLast()
}
func peek() -> T? {
return elements.last
}
var isEmpty: Bool {
return elements.isEmpty
}
}
// 实现 Queue
struct Queue<T> {
private var elements: [T] = []
mutating func enqueue(_ element: T) {
elements.append(element)
}
mutating func dequeue() -> T? {
return elements.isEmpty ? nil : elements.removeFirst()
}
func peek() -> T? {
return elements.first
}
var isEmpty: Bool {
return elements.isEmpty
}
}
2. 避免标准库臃肿
Swift 的设计哲学之一是保持标准库的精简和高效。如果每种数据结构都在标准库中提供实现,会导致标准库变得非常庞大和复杂。相反,Swift 鼓励开发者根据具体需求自己实现或使用第三方库。
3. 泛型与扩展
Swift 的泛型和扩展机制使得开发者可以很方便地定义自己的数据结构。通过泛型,可以实现类型安全的 Stack 和 Queue,而不需要依赖标准库中的实现。
4. 社区与第三方库支持
Swift 社区中有很多高质量的第三方库提供了各种数据结构的实现,例如 Swift Algorithm Club 就包含了丰富的数据结构和算法的实现。这种模式让标准库保持精简的同时,也能满足开发者的多样化需求。
结论
虽然 Swift 标准库没有原生支持 Stack 和 Queue 数据结构,但通过利用 Swift 强大的泛型和扩展机制,开发者可以很容易地自己实现这些数据结构。再加上丰富的第三方库支持,开发者可以根据需要选择最适合自己的解决方案。