图解Stack数据结构设计与应用案例

282 阅读4分钟

image.png

Stack 是 Java 中的一个类,它继承自 Vector 并实现了一个后进先出(LIFO)的栈数据结构。Stack 提供了基本的栈操作,如 push(入栈)、pop(出栈)、peek(查看栈顶元素)和 empty(检查栈是否为空)。由于 Stack 是基于 Vector 实现的,它是线程安全的,但在单线程环境中可能不如使用 Deque 实现的栈那样高效。Stack 通常用于实现算法和数据结构中的栈操作,以及在需要后进先出行为的场景中。

1、Stack

Stack 是一个后进先出(LIFO)的数据结构,通常使用数组或链表来实现。在 Java 中,Stack 类继承自 Vector,因此它是线程安全的。

设计思考:
  1. 需求场景
    • 在编程中,经常需要一种数据结构来支持后进先出(LIFO)的操作,例如在算法实现中,如深度优先搜索、递归算法、函数调用栈等。
    • 适用于需要跟踪最近添加的元素,或者需要撤销操作的场景,如文本编辑器的撤销功能。
  2. 现有技术局限性
    • 基本数组或固定大小的数据结构不支持 LIFO 操作,或者在进行这类操作时效率不高。
    • 需要一种数据结构能够快速地从一端添加和移除元素,同时能够轻松地检查栈顶元素。
  3. 技术融合
    • Stack 融合了动态数组的概念和 LIFO 操作的特性,提供了一个可以动态增长和收缩的栈结构。
  4. 设计理念
    • Stack 设计为一个简单的数据结构,它提供了一系列方法来支持 LIFO 操作,如 push(入栈)、pop(出栈)、peek(查看栈顶元素)和 isEmpty(检查栈是否为空)。
  5. 实现方式
    • Stack 内部使用 Vector 来存储元素,由于 Vector 是同步的,Stack 也是线程安全的。Stack 定义了一系列方法来操作 Vector 的顶部元素,从而实现栈的操作。
2、 数据结构

image.png

图说明:
  • Stack:表示 Stack 类的实例,是一个后进先出的数据结构。
  • Element ArrayStack 使用一个数组来存储栈中的元素。
  • Top Marker:表示栈顶的位置,指向数组中的最后一个元素,即栈顶元素。
  • Element 0, Element 1, ..., Element N-1:数组中的每个位置存储一个元素,这些元素可以是任意类型的对象。
  • Null:在数组的末尾,表示数组的当前大小。
3、 执行流程

image.png

图说明:
  • 创建 Stack 实例:初始化 Stack 对象。
  • 执行操作:决定要执行的操作类型,可以是入栈(push)、出栈(pop)或查看栈顶元素(peek)。
  • 入栈操作(push) :执行将元素添加到栈顶的操作。
  • 检查栈满:检查栈是否已满,如果已满则不能执行入栈操作。
  • 将元素压入栈顶:将元素添加到栈顶。
  • 出栈操作(pop) :执行移除栈顶元素的操作。
  • 检查栈空:检查栈是否为空,如果为空则不能执行出栈操作。
  • 移除栈顶元素:从栈中移除栈顶元素。
  • 返回被移除的元素:返回被移除的栈顶元素。
  • 查看栈顶元素(peek) :执行查看但不移除栈顶元素的操作。
  • 获取栈顶元素:获取栈顶元素的引用。
  • 返回栈顶元素:返回栈顶元素的值。

4、优点

  1. LIFO 操作的高效性
    • 提供了常数时间复杂度的 push 和 pop 操作。
  2. 线程安全
    • 由于基于 Vector 实现,Stack 是线程安全的。
  3. 简单易用
    • 提供了直观的 API 来执行栈操作。

5、缺点

  1. 性能开销
    • 由于 Vector 的同步特性,可能会在高并发环境下导致性能瓶颈。
  2. 扩展性有限
    • 在高并发环境下,Stack 的全局锁可能导致性能问题。

6、使用场景

  • 算法实现
    • 适用于需要 LIFO 操作的算法,如深度优先搜索、递归算法等。
  • 撤销功能
    • 在需要撤销最近操作的场景中,如文本编辑器的撤销功能。

7、类设计

image.png

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());
        }
    }
}