用數組表示棧
選擇用數組表示棧內容必須預先估計棧的最大容量。在Java中,數組一旦創建,其大小是無法改變的,而數組設置過大可能會浪費大量內存,設置過小又可能會溢出。
所以我們希望能夠動態調整數組a[i]的大小,使得它既足以保存所有元素,又不至於浪費過多的空間。
首先,實現一個方法將棧移動到另一個大小不同的數組中。
1 private void resize(int max) { 2 3 Item[] temp = (Item[]) new Object[max]; 4 for (int i = 0; i < N; i++) { 5 temp[i] = a[i]; 6 } 7 a = temp; 8 }
然后在push()中檢測數組是否太小。如果沒有多余的空間,就將數組的長度加倍。
1 public void push(Item item) { 2 3 if (N == a.length) resize(2*a.length); 4 a[N++] = item; 5 6 }
類似的,在pop()中,先刪除棧頂元素,然后如果棧大小小於數組的四分之一就將數組的長度減半(這樣數組長度被減半之后約為半滿,在下次需要改變數組大小之前仍然能夠進行多次push()和pop()操作)。
1 public Item pop() { 2 3 Item item = a[--N]; 4 a[N] = null; //避免對象游離(見標注) 5 6 if (N > 0 && N == a.length/4) resize(a.length/2); 7 return item; 8 }
注:在對pop()的實現中,被彈出的元素的引用仍然存在於數組中。它永遠不會再被訪問了,但Java的垃圾回收集器無法知道這一點,除非該引用被覆蓋。這種情況(保存一個不需要的對象的引用)稱為游離。
在這里,只需將被彈出的數組元素的值設置為null即可。
下面給出用數組表示棧的代碼實現:
下壓(LIFO)棧(能夠動態調整數組大小的實現):
1 public class ResizingArrayStack<Item> implements Iterable<Item> { 2 private Item[] a; 3 private int N; 4 5 public ResizingArrayStack() { 6 a = (Item[]) new Object[2]; 7 N = 0; 8 } 9 10 11 public boolean isEmpty() { 12 return N == 0; 13 } 14 15 16 public int size() { 17 return N; 18 } 19 20 21 private void resize(int capacity) { 22 assert capacity >= N; 23 Item[] temp = (Item[]) new Object[capacity]; 24 for (int i = 0; i < N; i++) { 25 temp[i] = a[i]; 26 } 27 a = temp; 28 } 29 30 31 public void push(Item item) { 32 if (N == a.length) resize(2*a.length); 33 a[N++] = item; 34 } 35 36 public Item pop() { 37 Item item = a[--N]; 38 a[N] = null; 39 40 if (N > 0 && N == a.length/4) resize(a.length/2); 41 return item; 42 } 43 44 45 public Item peek() { 46 return a[--N]; 47 } 48 49 50 public Iterator<Item> iterator() { 51 return new ReverseArrayIterator(); 52 } 53 54 private class ReverseArrayIterator implements Iterator<Item> { 55 private int i; 56 57 public ReverseArrayIterator() { 58 i = N; 59 } 60 61 public boolean hasNext() { 62 return i >= 0; 63 } 64 65 public void remove() { 66 throw new UnsupportedOperationException(); 67 } 68 69 public Item next() { 70 return a[--i]; 71 } 72 } 73 74 }
用數組表示棧的優點:
每項操作的用時都與集合大小無關;
空間需求總是不超過集合大小乘以一個常數。
用數組表示棧的缺點:
某些push()和pop()操作會調整數組的大小:這項操作的耗時和棧大小成正比。