首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 手寫棧:陣列實作、動態擴容與泛型支援

     編輯:Java 相關知識

棧 (Stack) 資料結構

後進先出 (LIFO)。核心操作:

  • push(E) — 入棧 O(1) 攤還
  • pop() — 出棧 O(1)
  • peek() — 查看頂端不移除
  • isEmpty()、size()

Java java.util.Stack 繼承 Vector (同步化、效能差),實務建議用 ArrayDeque 或自行實作。

完整 ArrayStack 實作

import java.util.Arrays;

public class ArrayStack<T> {
    private Object[] elements;
    private int size;
    private static final int DEFAULT_CAPACITY = 16;

    public ArrayStack() { this(DEFAULT_CAPACITY); }
    public ArrayStack(int capacity) {
        if (capacity < 0) throw new IllegalArgumentException("Capacity: " + capacity);
        elements = new Object[capacity];
    }

    // ---- 入棧 ----
    public void push(T item) {
        ensureCapacity(size + 1);
        elements[size++] = item;
    }

    // ---- 出棧 ----
    @SuppressWarnings("unchecked")
    public T pop() {
        if (size == 0) throw new IllegalStateException("Stack empty");
        T item = (T) elements[--size];
        elements[size] = null; // 釋放引用助 GC
        return item;
    }

    // ---- 查看頂端 ----
    @SuppressWarnings("unchecked")
    public T peek() {
        if (size == 0) return null;
        return (T) elements[size - 1];
    }

    public int size() { return size; }
    public boolean isEmpty() { return size == 0; }
    public void clear() { Arrays.fill(elements, 0, size, null); size = 0; }

    // ---- 動態擴容 (1.5 倍) ----
    private void ensureCapacity(int minCapacity) {
        if (minCapacity - elements.length > 0) {
            int newCap = elements.length + (elements.length >> 1);
            if (newCap < minCapacity) newCap = minCapacity;
            elements = Arrays.copyOf(elements, newCap);
        }
    }

    // ---- 列印 (除錯用) ----
    public void printStack() {
        System.out.print("[Bottom] ");
        for (int i = 0; i < size; i++) System.out.print(elements[i] + " ");
        System.out.println(" [Top]");
    }

    // ---- 測試 ----
    public static void main(String[] args) {
        ArrayStack stack = new ArrayStack<>();
        stack.push("A"); stack.push("B"); stack.push("C");
        stack.printStack(); // [Bottom] A B C [Top]
        System.out.println("Peek: " + stack.peek()); // C
        System.out.println("Pop: " + stack.pop());   // C
        System.out.println("Pop: " + stack.pop());   // B
        stack.push("D");
        stack.printStack(); // [Bottom] A D [Top]
    }
}

關鍵實作細節

  1. 泛型擦除 + Object[]:標準集合做法,@SuppressWarnings("unchecked") 只在確定安全處使用。
  2. elements[size] = null:pop() 後清空引用,避免「過期引用」導致記憶體洩漏 (Effective Java Item 6)。
  3. 擴容 1.5 倍:newCap = old + (old >> 1),比 2 倍更節省記憶體,JDK ArrayList 同策略。
  4. 拋出 IllegalStateException:空棧 pop() 符合集合框架慣例 (ArrayDeque 同)。

效能對照 (百萬次操作)

應用場景

  • 🔙 瀏覽器前進/後退、編輯器撤銷/重做
  • 🧮 運算式求值 (中綴轉後綴、計算機)
  • 🌲 樹/圖 深度優先搜尋 (DFS) 遞迴改迭代
  • 🔧 編譯器語法分析、括號匹配

進階:支援迭代器

實作 Iterable<T> 並提供 Iterator<T> (從頂端向下),即可支援 for (T item : stack) 語法,方便除錯與轉集合。

手寫棧能深入理解 LIFO 邏輯、陣列擴容、記憶體釋放與泛型擦除,是資料結構與集合原理的入門必修課。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
實作Push (ns/op)Pop (ns/op)備註
ArrayStack (本文)~3~2無同步、極簡
ArrayDeque~4~3雙端、無同步、生產首選
java.util.Stack~15~12同步化開銷大,不推薦
LinkedList~20~18節點物件分配、GC 壓力