Stack 是 Java 中的一个类,它继承自 Vector 并实现了一个后进先出(LIFO)的栈数据结构。Stack 提供了基本的栈操作,如 push(入栈)、pop(出栈)、peek(查看栈顶元素)和 empty(检查栈是否为空)。由于 Stack 是基于 Vector 实现的,它是线程安全的,但在单线程环境中可能不如使用 Deque 实现的栈那样高效。Stack 通常用于实现算法和数据结构中的栈操作,以及在需要后进先出行为的场景中。
1、Stack
Stack 是一个后进先出(LIFO)的数据结构,通常使用数组或链表来实现。在 Java 中,Stack 类继承自 Vector,因此它是线程安全的。
设计思考:
- 需求场景:
- 在编程中,经常需要一种数据结构来支持后进先出(LIFO)的操作,例如在算法实现中,如深度优先搜索、递归算法、函数调用栈等。
- 适用于需要跟踪最近添加的元素,或者需要撤销操作的场景,如文本编辑器的撤销功能。
- 现有技术局限性:
- 基本数组或固定大小的数据结构不支持 LIFO 操作,或者在进行这类操作时效率不高。
- 需要一种数据结构能够快速地从一端添加和移除元素,同时能够轻松地检查栈顶元素。
- 技术融合:
- Stack 融合了动态数组的概念和 LIFO 操作的特性,提供了一个可以动态增长和收缩的栈结构。
- 设计理念:
- Stack 设计为一个简单的数据结构,它提供了一系列方法来支持 LIFO 操作,如
push(入栈)、pop(出栈)、peek(查看栈顶元素)和isEmpty(检查栈是否为空)。
- Stack 设计为一个简单的数据结构,它提供了一系列方法来支持 LIFO 操作,如
- 实现方式:
- Stack 内部使用
Vector来存储元素,由于Vector是同步的,Stack 也是线程安全的。Stack 定义了一系列方法来操作Vector的顶部元素,从而实现栈的操作。
- Stack 内部使用
2、 数据结构
图说明:
- Stack:表示
Stack类的实例,是一个后进先出的数据结构。 - Element Array:
Stack使用一个数组来存储栈中的元素。 - Top Marker:表示栈顶的位置,指向数组中的最后一个元素,即栈顶元素。
- Element 0, Element 1, ..., Element N-1:数组中的每个位置存储一个元素,这些元素可以是任意类型的对象。
- Null:在数组的末尾,表示数组的当前大小。
3、 执行流程
图说明:
- 创建 Stack 实例:初始化
Stack对象。 - 执行操作:决定要执行的操作类型,可以是入栈(push)、出栈(pop)或查看栈顶元素(peek)。
- 入栈操作(push) :执行将元素添加到栈顶的操作。
- 检查栈满:检查栈是否已满,如果已满则不能执行入栈操作。
- 将元素压入栈顶:将元素添加到栈顶。
- 出栈操作(pop) :执行移除栈顶元素的操作。
- 检查栈空:检查栈是否为空,如果为空则不能执行出栈操作。
- 移除栈顶元素:从栈中移除栈顶元素。
- 返回被移除的元素:返回被移除的栈顶元素。
- 查看栈顶元素(peek) :执行查看但不移除栈顶元素的操作。
- 获取栈顶元素:获取栈顶元素的引用。
- 返回栈顶元素:返回栈顶元素的值。
4、优点
- LIFO 操作的高效性:
- 提供了常数时间复杂度的
push和pop操作。
- 提供了常数时间复杂度的
- 线程安全:
- 由于基于
Vector实现,Stack 是线程安全的。
- 由于基于
- 简单易用:
- 提供了直观的 API 来执行栈操作。
5、缺点
- 性能开销:
- 由于
Vector的同步特性,可能会在高并发环境下导致性能瓶颈。
- 由于
- 扩展性有限:
- 在高并发环境下,Stack 的全局锁可能导致性能问题。
6、使用场景
- 算法实现:
- 适用于需要 LIFO 操作的算法,如深度优先搜索、递归算法等。
- 撤销功能:
- 在需要撤销最近操作的场景中,如文本编辑器的撤销功能。
7、类设计
8、应用案例
Stack 是一个后进先出(LIFO)的数据结构,通常使用数组或链表来实现。在 Java 中, Stack 类继承自 Vector,因此它是线程安全的。
Stack 类经常被用于需要动态数组和线程安全的场景。这是一个简单的库存管理系统,用于跟踪仓库中的商品数量:
import java.util.Enumeration;
import java.util.Vector;
// 商品类,用于表示仓库中的单个商品
class Product {
private String id;
private String name;
private int quantity;
public Product(String id, String name, int quantity) {
this.id = id;
this.name = name;
this.quantity = quantity;
}
// 省略 getter 和 setter 方法
}
// 库存管理系统类
class InventoryManagementSystem {
private Vector<Product> products;
public InventoryManagementSystem() {
products = new Vector<>();
}
// 添加商品到库存
public void addProduct(Product product) {
products.add(product);
}
// 更新商品数量
public void updateProductQuantity(String id, int newQuantity) {
for (Product product : products) {
if (product.getId().equals(id)) {
product.setQuantity(newQuantity);
break;
}
}
}
// 获取所有商品的列表
public Enumeration<Product> getProducts() {
return products.elements();
}
public static void main(String[] args) {
InventoryManagementSystem ims = new InventoryManagementSystem();
// 添加一些商品到库存
ims.addProduct(new Product("001", "Apple", 100));
ims.addProduct(new Product("002", "Banana", 150));
ims.addProduct(new Product("003", "Orange", 200));
// 更新特定商品的数量
ims.updateProductQuantity("002", 120);
// 打印所有商品的信息
Enumeration<Product> products = ims.getProducts();
while (products.hasMoreElements()) {
Product product = products.nextElement();
System.out.println("ID: " + product.getId() + ", Name: " + product.getName() + ", Quantity: " + product.getQuantity());
}
}
}