Java實現一個棧就這麼簡單

karspb發表於2021-09-09

棧定義

棧是一種基於後進先出(LIFO)策略的集合型別。本章討論如何使用Java語言實現一個基本的棧。一個棧容器要求提供入棧操作,出棧操作,獲取棧大小和判斷棧是否為空操作。抽象資料型別可定義為:

public interface Stack {    /*
    *  判斷棧是否為空。
    */
    public boolean isEmpty();    /*
    *  獲取棧大小。
    */
    public int size();    /*
    *  入棧。
    */
    public void push(Item item);    /*
    *  出棧。
    */
    public Item pop();
}

陣列實現

棧元素儲存在陣列中是一種基本的實現方式。內部定義一個陣列[]a用於存在入棧的元素,整數N儲存當前元素數量。

public class ArrayStack implements Stack {    /**
    * 儲存棧元素
    */
    private Item[] a = (Item[]) new Object[1];    /**
    * 棧元素數量
    */
    private int N;    @Override
    public boolean isEmpty() {        return N == 0;
    }    @Override
    public int size() {        return N;
    }    @Override
    public void push(Item item) {
        a[N++] = item;
    }    @Override
    public Item pop() {
        Item item = a[--N];
        a[N] = null;        return item;
    }
}

選擇用陣列標示棧內容必須先預估棧最大容量大小。在Java中,陣列一旦建立,其大小就不能改變。在實際應用中,我們一般無法在建立棧時確定其大小。如果太小,會導致陣列越界,如果太大,則會浪費記憶體空間。因此,我們需要在入棧和出棧中動態的調整資料大小。

入棧時透過檢查棧大小N和陣列大小a.length是否相等來檢查是否能夠容納新的元素。如果沒有多餘的空間,將陣列的的長度加倍。
出棧時檢查棧大小是否小於陣列的四分之一,如果滿足則把陣列大小減半。

public class ResizingArrayStack implements Stack {

    private Item[] a = (Item[]) new Object[1];    private int N = 0;    public boolean isEmpty() {        return N == 0;
    }    public int size() {        return N;
    }    public void push(Item item) {        if (N == a.length) {
            resize(2 * a.length);
        }
        a[N++] = item;
    }    private void resize(int max) {
        Item[] temp = (Item[]) new Object[max];
        System.arraycopy(a, 0, temp, 0, N);
        a = temp;
    }    public Item pop() {
        Item item = a[--N];
        a[N] = null;  // 避免物件遊離
        if (N > 0 && N == a.length / 4) {
            resize(a.length / 2);
        }        return item;
    }    public static void main(String[] args) {
        ResizingArrayStack stack = new ResizingArrayStack();        stack.push("ye");        stack.push("c");        stack.push("l");

        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
    }
}

陣列實現的缺點在於某些push()和pop()操作會調整陣列的大小:這項操作的耗時和棧大小成正比。為了克服這個缺點,可以採用連結串列實現棧。

連結串列實現

連結串列是一種遞迴的資料結構,它或者為空,或者指向一個節點的引用,該節點含有一個泛型的元素和一個指向另一個連結串列的結構。

節點的抽象資料型別可以表示為:

private class Node{
    /**
     * 儲存資料
     */
    Item item;    /**
     * 下一個節點引用
     */
    Node next;
}

連結串列實現時用一個節點表示棧頂元素,整數N記錄棧大小。入棧時新節點的下一個節點引用指向原來的棧頂節點,出棧時棧頂元素指向原來棧頂元素的下一個節點。

public class LinkedStack implements Stack {    /**
    * 棧頂
    */
    private Node first;    /**
    * 元素數量
    */
    private int N;    private class Node {
        Item item;
        Node next;
    }    @Override
    public boolean isEmpty() {        return first == null; // or N == 0;
    }    @Override
    public int size() {        return N;
    }    @Override
    public void push(Item item) {        // 棧頂新增元素
        Node oldFirst = first;
        first = new Node();
        first.item = item;
        first.next = oldFirst;
        N++;
    }    @Override
    public Item pop() {        // 棧頂刪除元素
        Item item = first.item;
        first = first.next;
        N--;        return item;
    }
}

在結構化儲存資料集時,連結串列是陣列的一種重要替代方式。它們各有優點和缺點,我們應該根據實際情況選擇合適的實現。



作者:葉春林
連結:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2001/viewspace-2810623/,如需轉載,請註明出處,否則將追究法律責任。

相關文章