堆栈拥有两种存储方式:顺序存储和链式存储。本文介绍堆栈了顺序存储方式。
堆栈简称为栈,是线性表的一种特殊表现形式。堆栈只能够在表的一端进行插入/删除操作,允许操作的一端称为栈顶,不允许操作的一端称为栈底。栈的一个一定要记住的特点是:先进后出!下图表示了堆栈的顺序存储方式。
假设用一个长度为5的数组a[5]来描述堆栈,其中a[0]表示栈底,a[4]表示栈的“最高点”,并采用top来指向堆栈的栈顶元素在数组中的位置。当堆栈为空(图a)时,数组中没有任何元素,此时top的值为-1;当将A压入堆栈(图b)时,相当于将a[0]赋值为A,此时将top指向0;当将B压入堆栈(图c)时,相当于将a[1]赋值为B,此时将top指向1;当需要从堆栈中弹出元素时,因为top指向的元素为B,因此先将B弹出(图d),并将top指向0;当需要再次弹出元素时,将A弹出(图e),并将top指向-1,此时表明堆栈已经为空了。
堆栈常用的操作方式有:查找栈顶元素、弹出栈顶元素、向栈中压入元素、判断栈空、判断栈满等。笔者从面向对象设计的角度出发,将栈看做一个对象,并定义其操作方法,代码如下:
public class Heap {
/**
* 用于表示堆栈的数组
*/
private Object[] a = new Object[100];
/**
* 用于表示栈顶的位置
*/
private int top = -1;
/**
* 判断是否栈空
*
* @return 如果栈空,返回true;否则返回false
*/
public boolean isEmpty() {
return top == -1;
}
/**
* 判断是否栈满。因为该堆栈最大可存放100个元素,因此当top为99时,说明堆栈已经满了
*
* @return 如果栈满,返回true;否则返回false
*/
public boolean isFull() {
return top == 99;
}
/**
* 将元素data压入堆栈中
*
* @param data 需要压入堆栈的元素
* @return 如果压入成功,返回true;否则,返回false
*/
public boolean push(Object data) {
if(isFull()) {
return false;
}
else {
a[++top] = data;
return true;
}
}
/**
* 弹出堆栈的栈顶元素
*
* @return 如果堆栈不为空,则弹出栈顶元素;否则,返回空值
*/
public Object pop() {
if(isEmpty()) {
return null;
}
else {
return a[top--];
}
}
/**
* 获取堆栈的栈顶元素
*
* @return 如果堆栈不为空,获取栈顶元素;否则,返回空值
*/
public Object get() {
if(isEmpty()) {
return null;
}
else {
return a[top];
}
}
}
顺序存储的局限性:
1.需要事先知道堆栈的最大元素数,如果事先并没有合理规划好堆栈容量的话,就会造成空间的浪费,或者堆栈的溢出。
2.需要在内存空间中分配一段连续的空间,因此对内存空间的当前状态有要求,如果内存中不存在这样一段连续空间,则无法分配栈空间。
3.对于多个堆栈共享一段内存空间的情况,如果需要调整存储空间时,元素将会发生大规模移动,时间复杂度较高。