在Java编程中,堆栈(Stack)是一种重要的数据结构,它遵循后进先出(LIFO,Last In First Out)的原则,即最后一个入栈的元素总是第一个出栈。Java标准库并没有直接提供一个名为“Stack”的类,但我们可以使用java.util.Stack类或者更常用的java.util.Deque接口(如ArrayDeque或LinkedList)来实现堆栈的功能。由于java.util.Stack类被认为是遗留类,因此在现代编程中更推荐使用Deque接口的实现类。
Stack的基本操作
- push(E item) :将元素压入栈顶。
- pop() :移除栈顶元素并返回该元素。如果此堆栈为空,则抛出
NoSuchElementException。 - peek() :检索但不移除此堆栈的顶部元素。如果此堆栈为空,则抛出
NoSuchElementException。 - empty() :测试此堆栈是否为空。
- search(Object o) :返回对象在此堆栈中的从1开始的偏移量;如果此堆栈不包含该对象,则返回-1。
使用Deque接口实现Stack
由于Deque接口提供了双端队列的功能,我们可以使用其push, pop, 和 peek等方法来实现堆栈的功能。以下是一个使用ArrayDeque实现堆栈的示例:
java复制代码
import java.util.ArrayDeque;
import java.util.Deque;
public class StackExample {
private Deque<Integer> stack;
public StackExample() {
stack = new ArrayDeque<>();
}
public void push(int item) {
stack.push(item);
}
public int pop() {
if (!stack.isEmpty()) {
return stack.pop();
} else {
throw new EmptyStackException();
}
}
public int peek() {
if (!stack.isEmpty()) {
return stack.peek();
} else {
throw new EmptyStackException();
}
}
public boolean isEmpty() {
return stack.isEmpty();
}
public static void main(String[] args) {
StackExample stack = new StackExample();
stack.push(1);
stack.push(2);
stack.push(3);
System.out.println(stack.peek()); // 输出 3
System.out.println(stack.pop()); // 输出 3
System.out.println(stack.pop()); // 输出 2
System.out.println(stack.isEmpty()); // 输出 false
}
}
注意事项
- 异常处理:当调用
pop或peek方法时,如果堆栈为空,应该抛出EmptyStackException异常。 - 线程安全:
ArrayDeque和LinkedList等非线程安全的类在多线程环境中使用时需要额外的同步措施。如果需要线程安全的堆栈,可以使用java.util.concurrent.ConcurrentLinkedQueue或java.util.concurrent.Stack(尽管java.util.concurrent.Stack通常不被推荐,因为它扩展了遗留的Vector类)。 - 性能:堆栈操作(如push和pop)在数组实现和链表实现中通常具有常数时间复杂度(O(1))。但是,如果底层数据结构(如
ArrayList)在push操作时需要重新分配内存,则性能可能会受到影响。 - 应用场景:堆栈在许多场景中都非常有用,例如函数调用栈、浏览器的前进后退功能、撤销操作等。