前言
栈(Stack)是限定只能在一段进行插入和删除操作的线性表。
进行插入和删除操作的一端称为“栈顶”(top),另一端称为“栈底”(bottom)。
栈的插入操作称为“入栈”(push),栈的删除 操作称为“出栈”(pop)。
栈具有后进先出(LIFO),先进后出(FILO)的特性。
Stack类
Java工具包下的Stack类继承于Vector,由此可见Stack底层是由数组实现的。
Stack和Collection的关系如下图:
我们来看下Stack的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| package java.util;
public class Stack<E> extends Vector<E> {
public Stack() { }
public E push(E item) { addElement(item);
return item; }
public synchronized E pop() { E obj; int len = size();
obj = peek(); removeElementAt(len - 1);
return obj; }
public synchronized E peek() { int len = size();
if (len == 0) throw new EmptyStackException(); return elementAt(len - 1); }
public boolean empty() { return size() == 0; }
public synchronized int search(Object o) { int i = lastIndexOf(o);
if (i >= 0) { return size() - i; } return -1; } private static final long serialVersionUID = 1224463164541339165L; }
|
根据源码,可以发现Stack的方法调用了Vector类的方法,实现了线程安全。
我们主要看一下Vector里的下面三个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public synchronized void addElement(E obj) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = obj; } public synchronized void removeElementAt(int index) { modCount++; if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } else if (index < 0) { throw new ArrayIndexOutOfBoundsException(index); } int j = elementCount - index - 1; if (j > 0) { System.arraycopy(elementData, index + 1, elementData, index, j); } elementCount--; elementData[elementCount] = null; } public synchronized E elementAt(int index) { if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); }
return elementData(index); }
|
关联方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| private void ensureCapacityHelper(int minCapacity) { 如果长度超了就扩容 if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
|
实践
我们如何用数组实现自己的一个stack呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| public class Stack { private Object[] members; private int size; public Stack(int initCapacity) throws Exception{ if(initCapacity<=0) { throw new Exception(); } this.members=new Object[initCapacity]; } public Stack() { this.members=new Object[10]; } public synchronized void push(Object o){ ensureCapacity(size+1); members[size++]=o; } public synchronized Object pop() throws Exception{ if(size<=0) { throw new Exception(); } return members[--size]; } public synchronized Object peek() throws Exception{ if(size<=0) { throw new Exception(); } return members[size-1]; } private synchronized void ensureCapacity(int minCapacity) { if(minCapacity-members.length>0) { int oldCapacity = members.length; Object oldMembers=members; int newCapacity = 2 * oldCapacity ; if (newCapacity - minCapacity < 0) newCapacity = minCapacity; members=new Object[newCapacity]; System.arraycopy(oldMembers, 0, members, 0, size); oldMembers=null; } } }
|
以上代码就是一个简易的Stack的实现方式。
代码见: https://github.com/JavaZWT/sakuratears
总结
Stack类在编程过程中用到的不是很多,但是计算机栈内存机制遵循先进后出原则,学习Stack类,可以帮助我们加深对程序及数据结构的理解。