为什么我们需要知道栈的长度?
想象你在整理书架,有一摞书堆得整整齐齐。你很好奇这摞书一共有多少本,对吧?栈(Stack)也是一样的道理——它是编程中最基础也最常用的数据结构之一,遵循 LIFO(后进先出) 原则。
很多人以为栈只能用来压入和弹出元素,却忘了它还有一个重要属性:容量/长度。下面我用几种主流语言来详细讲解如何获取栈的长度,确保你无论用什么语言都能轻松上手。
Python 中的栈长度
Python 没有内置的 Stack 类,但我们通常用 列表(list) 来模拟栈,或者使用 collections.deque。获取长度的方式非常简单,用内置的 len() 函数即可。
# 方法一:用 list 模拟栈
stack = [10, 20, 30, 40, 50]
# 获取栈的长度
length = len(stack)
print(f"栈中的元素个数: {length}") # 输出: 栈中的元素个数: 5
# 再压入两个元素
stack.append(60)
stack.append(70)
print(f"压入后栈的长度: {len(stack)}") # 输出: 压入后栈的长度: 7
# 弹出一个元素
stack.pop()
print(f"弹出后栈的长度: {len(stack)}") # 输出: 弹出后栈的长度: 6
小贴士:
len()的时间复杂度是 O(1),因为 Python 的列表会自己维护长度,不需要遍历整个栈。
用 deque 模拟栈(更高效)
当栈的操作频繁时,deque 比 list 更快,尤其是从两端操作时。
from collections import deque
# 创建栈
stack = deque([1, 2, 3, 4, 5])
# 获取长度
print(f"当前栈长度: {len(stack)}") # 输出: 当前栈长度: 5
# 压栈
stack.append(6)
print(f"压栈后长度: {len(stack)}") # 输出: 压栈后栈长度: 6
# 弹栈
stack.pop()
print(f"弹栈后长度: {len(stack)}") # 输出: 弹栈后栈长度: 5
Java 中的栈长度
Java 有专门的 Stack 类(继承自 Vector),也推荐使用 Deque 接口配合 ArrayDeque 实现栈。
import java.util.Stack;
import java.util.Deque;
import java.util.ArrayDeque;
public class StackLengthExample {
public static void main(String[] args) {
// 方法一:使用 java.util.Stack
Stack<Integer> stack = new Stack<>();
stack.push(10);
stack.push(20);
stack.push(30);
// 获取栈的长度(元素个数)
int size = stack.size();
System.out.println("栈的长度: " + size); // 输出: 栈的长度: 3
// 方法二:使用 Deque(推荐方式)
Deque<Integer> dequeStack = new ArrayDeque<>();
dequeStack.push(100);
dequeStack.push(200);
dequeStack.push(300);
dequeStack.push(400);
int dequeSize = dequeStack.size();
System.out.println("Deque 栈的长度: " + dequeSize); // 输出: Deque 栈的长度: 4
}
}
重点:Java 的
Stack.size()返回的是当前栈中元素的个数,不是最大容量。这一点很多人会混淆,记住:长度 = 当前有多少个元素。
C++ 中的栈长度
C++ STL 提供了 std::stack 容器适配器,它本身不暴露底层容器的大小方法,但我们可以通过 .size() 成员函数直接获取。
#include <iostream>
#include <stack>
int main() {
std::stack<int> st;
// 压入元素
st.push(10);
st.push(20);
st.push(30);
st.push(40);
// 获取栈的长度
std::cout << "栈的长度: " << st.size() << std::endl; // 输出: 栈的长度: 4
// 弹出一个元素
st.pop();
std::cout << "弹出一个后长度: " << st.size() << std::endl; // 输出: 弹出一个后长度: 3
// 检查栈是否为空
if (st.empty()) {
std::cout << "栈是空的" << std::endl;
} else {
std::cout << "栈不为空,当前长度: " << st.size() << std::endl;
}
return 0;
}
注意:
std::stack的size()返回类型是size_t(无符号整数),所以在做比较时要注意不要和有符号整数混用,避免意外错误。
JavaScript 中的栈长度
JavaScript 没有内置的 Stack 类,我们用数组来模拟。获取长度用 .length 属性。
// 用数组模拟栈
const stack = [];
// 压栈
stack.push(10);
stack.push(20);
stack.push(30);
stack.push(40);
// 获取栈的长度
console.log(`当前栈长度: ${stack.length}`); // 输出: 当前栈长度: 4
// 弹栈
const top = stack.pop();
console.log(`弹出的元素: ${top}, 剩余长度: ${stack.length}`); // 输出: 弹出的元素: 40, 剩余长度: 3
// 查看栈顶元素(不弹出)
console.log(`栈顶元素: ${stack[stack.length - 1]}`); // 输出: 栈顶元素: 30
实战场景:用栈长度解决实际问题
下面这个例子展示了栈长度在实际开发中的典型用途:检查括号匹配。
def is_valid_parentheses(expression: str) -> bool:
"""
使用栈检查括号是否有效匹配
栈的长度在这里起到了关键作用:
- 遇到开括号时压栈
- 遇到闭括号时弹栈并检查匹配
- 最后栈为空说明全部匹配
"""
stack = []
mapping = {')': '(', '}': '{', ']': '['}
for char in expression:
if char in mapping.values(): # 是开括号
stack.append(char)
elif char in mapping.keys(): # 是闭括号
if len(stack) == 0: # 栈为空,没有对应的开括号
return False
top = stack.pop()
if top != mapping[char]:
return False
# 最后栈必须为空才算有效
return len(stack) == 0
# 测试用例
print(is_valid_parentheses("()")) # True
print(is_valid_parentheses("()[]{}")) # True
print(is_valid_parentheses("(]")) # False
print(is_valid_parentheses("([)]")) # False
print(is_valid_parentheses("{[]}")) # True
在这个例子中,栈的长度决定了我们是否能正确判断括号是否匹配。如果栈的长度为 0 时又遇到了闭括号,说明缺少对应的开括号;如果最后栈的长度不为 0,说明有多余的开括号没有闭合。
各语言获取栈长度的方法汇总
| 语言 | 栈的实现方式 | 获取长度的方法 | 时间复杂度 |
|---|---|---|---|
| Python | list 或 deque |
len(stack) |
O(1) |
| Java | Stack<Integer> |
stack.size() |
O(1) |
| Java | ArrayDeque<Integer> |
deque.size() |
O(1) |
| C++ | std::stack<int> |
st.size() |
O(1) |
| JavaScript | Array |
stack.length |
O(1) |
常见误区澄清
误区一:栈的长度 == 栈的容量
这是完全错误的。栈的长度是指当前栈中实际存放的元素个数,而容量是指栈最多能容纳多少个元素。比如在 Java 的 Stack 中,你可以无限 push,长度会一直增长,直到内存不足。
误区二:获取栈长度需要遍历
不需要!几乎所有主流语言的栈实现都会在内部维护一个计数器,所以 size() 或 len() 都是 O(1) 的操作,直接返回即可,不需要遍历。
误区三:空栈的长度是 -1
不对。空栈的长度是 0。当你从一个有元素的栈中把所有元素都弹出后,栈的长度变为 0,而不是 -1 或其他负数。
总结
获取栈的长度是编程中最基础也最实用的操作之一。无论你用 Python 的 len()、Java 的 .size()、C++ 的 .size() 还是 JavaScript 的 .length,核心思路都是一样的:栈会在内部维护元素个数,直接查询即可,无需遍历。
记住这个关键点:栈的长度 = 当前栈中实际存在的元素数量,它随着 push 操作增加,随着 pop 操作减少。把这个概念理清楚,你在处理栈相关问题时会更加得心应手。
