用数组实现栈
用数组表示栈
选择用数组表示栈内容必须预先估计栈的最大容量。在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()操作会调整数组的大小:这项操作的耗时和栈大小成正比。