java 怎么写一个stack

java 怎么写一个stack

Java写栈(Stack):可继承java.util.Stack类;或基于Deque接口实现,如用ArrayDeque作底层存储,通过push( 入栈、pop( 出栈...

优惠价格:¥ 0.00
当前位置:首页 > 后端开发 > java 怎么写一个stack
详情介绍
Java写栈(Stack):可继承 java.util.Stack类;或基于 Deque接口实现,如用 ArrayDeque作底层存储,通过 push()入栈、 pop()出栈

是用Java实现栈的详细步骤和完整示例,包括核心逻辑、边界处理及扩展功能:

基础结构设计

  1. 成员变量定义

    • private int[] elements; // 存储元素的数组
    • private int top = -1; // 栈顶指针(初始为-1表示空栈)
    • private static final int DEFAULT_CAPACITY = 10; // 默认容量
  2. 构造函数

    public Stack() {
     this(DEFAULT_CAPACITY); // 调用带参构造
    }
    public Stack(int capacity) {
     if (capacity <= 0) {
         throw new IllegalArgumentException("容量必须大于0");
     }
     elements = new int[capacity]; // 根据传入容量创建数组
    }
  3. 核心方法实现
    | 方法名 | 功能描述 | 关键代码逻辑 | 异常处理 |
    |————–|——————————|——————————————————————————|————————–|
    | push(item) | 将元素压入栈顶 | if (isFull()) throw new StackOverflowError();<br>elements[++top] = item; | 栈满时抛出异常 |
    | pop() | 移除并返回栈顶元素 | if (isEmpty()) throw new EmptyStackException();<br>return elements[top--]; | 栈空时抛出异常 |
    | peek() | 查看但不删除栈顶元素 | if (isEmpty()) throw new EmptyStackException();<br>return elements[top]; | 同上 |
    | size() | 获取当前元素数量 | return top + 1; | 无 |
    | isEmpty() | 判断是否为空栈 | return top == -1; | 无 |
    | isFull() | 判断是否已满 | return top == elements.length 1; | 无 |

关键细节解析

扩容机制优化(动态数组)

当栈空间不足时,可自动扩展底层数组容量,例如修改push方法:

public void push(int item) {
    if (isFull()) {
        // 创建新数组并复制旧数据
        int[] newArray = Arrays.copyOf(elements, elements.length  2);
        elements = newArray;
    }
    elements[++top] = item;
}
```此实现使栈的最大容量不再受限于初始化值,但会增加少量性能开销。
# 2. 泛型支持改造
若需存储任意类型数据,可将类改为泛型类:
```java
public class Stack<T> {
    private T[] data;          // 使用Object数组兼容所有类型
    @SuppressWarnings("unchecked")
    public Stack() {
        data = (T[]) new Object[DEFAULT_CAPACITY]; // 类型擦除技巧
    }
    // push/pop等方法相应调整参数类型为T
}
```注意需要添加`@SuppressWarnings("unchecked")`注解避免编译警告。
# 3. 迭代器实现(增强遍历能力)
通过实现`Iterable`接口支持增强for循环:
```java
public Iterator<Integer> iterator() {
    return new Iterator<Integer>() {
        private int current = 0;
        public boolean hasNext() { return current <= top; }
        public Integer next() { return data[current++]; }
    };
}
```使用时可直接调用`for (int num : stack) { ... }`进行遍历。
 三、完整代码示例
```java
public class IntStack {
    private int[] elements;
    private int top;
    private static final int DEFAULT_CAPACITY = 10;
    public IntStack() { this(DEFAULT_CAPACITY); }
    public IntStack(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException("非规容量");
        elements = new int[capacity];
        top = -1;
    }
    public void push(int value) {
        if (top == elements.length 1) {
            growCapacity();
        }
        elements[++top] = value;
    }
    private void growCapacity() {
        int newSize = elements.length  2;
        int[] newArray = Arrays.copyOf(elements, newSize);
        elements = newArray;
    }
    public int pop() throws EmptyStackException {
        if (isEmpty()) throw new EmptyStackException();
        return elements[top--];
    }
    public int peek() throws EmptyStackException {
        if (isEmpty()) throw new EmptyStackException();
        return elements[top];
    }
    public boolean isEmpty() { return top == -1; }
    public int size() { return top + 1; }
}

典型应用场景

  1. 表达式求值:利用后进先出特性处理运算符优先级(如括号匹配)
  2. 深度优先搜索:记录回溯路径时的节点访问顺序
  3. 函数调用模拟:手动管理递归过程的状态保存
  4. 撤销操作实现:历史记录的反向播放功能

常见误区警示

  1. 混淆栈与队列:确保只在队尾进行插入/删除操作(LIFO原则)
  2. 忽略空栈检查:所有出栈操作前必须验证非空状态
  3. 数组越界风险:动态扩容时注意新旧数组的数据迁移完整性
  4. 类型安全性问题:使用泛型时避免未经检查的类型转换

FAQs

Q1: 如果频繁进行大量数据的入栈出栈操作,应该选择哪种实现方式?
A: 推荐使用链表结构代替数组实现,因为链表在头部插入/删除的时间复杂度为O(1),而数组需要移动元素导致O(n)的时间消耗,Java标准库中的LinkedList就基于双向链表实现,其Deque接口提供的栈操作方法正是为此优化。

Q2: Java集合框架中的Stack类为什么被标记为遗留类?
A: 根据Oracle官方文档建议,应使用Deque接口的实现类(如ArrayDeque)替代传统Stack类,因为前者提供了更完善的迭代器实现和更好的性能表现,且遵循了现代集合框架的设计规范,例如ArrayDeque在作为栈使用时,所有操作的时间复杂度都是O(1),而旧版Stack的某些方法存在冗余设计

0