前言:
Stack一般来说用的比较少点,因为其数据结构特殊性,所以在一些特殊的场景,还是能发挥出巨大作用的。
Stack(栈):参照java.util.Stack的注释来看,它具有后进先出的特性(LIFO)。
从网络上截一个图(如有侵权,请联系作者),简单表示下链表结构
可以看到,其主要操作就是入栈和出栈操作,a0元素是最早入栈的,现在在栈底,an是最后一个入栈的,在栈顶,执行出栈操作时an先出来,最后才是a0
1.Stack结构分析
/**
* The Stack
class represents a last-in-first-out
* (LIFO) stack of objects.
*/
public
class Stack extends Vector {
可以看到,其继承了Vector,而Vector又是线程安全版的ArrayList,所以,其底层存储仍然是数组
2.构造方法
public Stack() {
}
构造比较简单,只有一个空参构造方法
3.基本操作 1)入栈操作
// Stack.push()
public E push(E item) {
// 直接调用了Vector.addElement()方法
addElement(item);
return item;
}
// Vector.addElement()
public synchronized void addElement(E obj) {
modCount++;
// 扩容,存放值到数组最后一位
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
入栈操作就是将数据添加到数组最后一位
2)查看栈顶元素操作
public synchronized E peek() {
int len = size();
if (len == 0)
throw new EmptyStackException();
// 获取数组最后一位的数据
return elementAt(len - 1);
}
3)出栈操作
public synchronized E pop() {
E obj;
int len = size();
// 1.获取站顶元素
obj = peek();
// 2.调用Vector.removeElementAt()
removeElementAt(len - 1);
return obj;
}
// Vector.removeElementAt()
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--;
// 将最后一位置为null
elementData[elementCount] = null; /* to let gc do its work */
}
可以看出,入栈出栈操作都是线程安全操作,基本操作都是交由Vector来处理的。
4)查询元素操作
public synchronized int search(Object o) {
// 交由Vector.lastIndexOf()处理
int i = lastIndexOf(o);
// 这一步比较有意思,如果获取到元素的索引位置
// 用size()减去其值,为什么要这样做呢?
if (i >= 0) {
return size() - i;
}
return -1;
}
// Vector.lastIndexOf()
// 遍历数组查询对象
public synchronized int lastIndexOf(Object o, int index) {
if (index >= elementCount)
throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
if (o == null) {
for (int i = index; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = index; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
注意:栈的查询返回的索引与数组查询返回的索引不同,为什么会有这么大的差距呢?
主要是因为它们的结构不同,对于数组的最后一个元素而言,相对栈而言是栈顶元素,index也就是1,所以获取元素在数组后的index后,还需要使用size()-index