栈(Stack)

栈(Stack)数据结构

栈是一种后进先出(LIFO, Last In First Out)的线性数据结构

类似于进电梯,先进后出(进电梯后别站在最边上哈,不然就先出了,哈哈~)
或者类似洗完,先洗好的放下面,后洗好的放上面,拿碗的时候要拿后洗好的。

核心特性

  1. LIFO原则:最后入栈的元素最先出栈
  2. 受限访问:只能从栈顶(top)进行插入和删除操作(只能一端进出,队列就是双端进出,一端进,一端出)
  3. 基本操作
    • push(压栈/入栈):在栈顶添加元素
    • pop(弹栈/出栈):移除并返回栈顶元素
    • peek/top(查看栈顶):返回栈顶元素但不移除
    • isEmpty:检查栈是否为空
    • size:获取栈中元素数量

栈的实现方式

1. 基于数组的实现

public class ArrayStack {
    private final int[] stackArray;
    private int top;
    private final int capacity;

    public ArrayStack(int size) {
        stackArray = new int[size];
        capacity = size;
        top = -1;
    }

    public void push(int item) {
        if (isFull()) {
            throw new RuntimeException("Stack is full");
        }
        stackArray[++top] = item;
    }

    public int pop() {
        if (isEmpty()) {
            throw new RuntimeException("Stack is empty");
        }
        return stackArray[top--];
    }

    public int peek() {
        if (isEmpty()) {
            throw new RuntimeException("Stack is empty");
        }
        return stackArray[top];
    }

    public boolean isEmpty() {
        return top == -1;
    }

    public boolean isFull() {
        return top == capacity - 1;
    }

    public int size() {
        return top + 1;
    }

    public static void main(String[] args) {
        ArrayStack stack = new ArrayStack(5);
        stack.push(1);
        stack.push(2);
        stack.push(3);

        System.out.println(stack.pop()); // 输出: 3
        System.out.println(stack.peek()); // 输出: 2
        System.out.println(stack.size()); // 输出: 2
    }
}

2. 基于链表的实现

public class LinkedListStack {
    private static class Node {
        int data;
        Node next;

        Node(int data) {
            this.data = data;
        }
    }

    private Node top;
    private int size;

    public void push(int data) {
        Node newNode = new Node(data);
        newNode.next = top;
        top = newNode;
        size++;
    }

    public int pop() {
        if (isEmpty()) {
            throw new RuntimeException("Stack is empty");
        }
        int data = top.data;
        top = top.next;
        size--;
        return data;
    }

    public int peek() {
        if (isEmpty()) {
            throw new RuntimeException("Stack is empty");
        }
        return top.data;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public static void main(String[] args) {
        LinkedListStack stack = new LinkedListStack();
        stack.push(10);
        stack.push(20);
        stack.push(30);

        System.out.println(stack.pop()); // 输出: 30
        System.out.println(stack.peek()); // 输出: 20
    }
}

时间复杂度

操作 数组实现时间复杂度 链表实现时间复杂度 说明
push() O(1) O(1) 数组实现:直接 arr[++top] = 插入节点
链表实现:新的节点置为头结点,下一个节点是原来的头结点
pop() O(1) O(1) 数组实现:可以直接返回 arr[top--](仅维护下标,元素其实还在)
链表实现:返回头结点,然后把下一个节点置为头结点
peek() O(1) O(1) 数组时间:直接访问 arr[top](下标不用维护)
链表实现:直接访问头节点
size() O(1) O(1) 数组实现:top+1(下标+1就是有效数据个数)
链表实现:直接访问 size 属性
empty() O(1) O(1) 数组实现:top是否等于-1(判断下标,从0开始,如果小于0就表明是空)
链表实现:头结点是否为空或size是否是0

JDK 中的栈

Stack 继承 Vector 数组实现,线程安全(所有方法都使用 synchronized 来同步)

ArrayDeque 数组实现,线程不安全,既具有栈的特性也具有队列的特性

posted @ 2025-04-26 17:34  CyrusHuang  阅读(31)  评论(0)    收藏  举报