栈和队列是两种重要的线性结构。从实际结构角度看,栈和队列也是线性表,其特殊性在于栈和队列的基本操作是线性表操作的子集,它们是操作受限的线性表,因此,可称为限定性的数据结构。但从数据类型的角度看,它们是和线性表大不相同的两类重要的抽象数据类型。由于它们广泛应用于软件系统,因此在面向对象的程序设计中,它们是多型数据类型。
3.1 栈
3.1.1 抽象数据类型栈的定义
栈是只限定在表尾进行插入和删除操作的线性表。因此,对于栈来说表尾有特殊含义,称为栈顶,相应地表头称为栈底。不含元素的栈称为空栈。
栈是先进后出的线性表(简称LIFO结构)。
栈的基本操作除了插入和删除外,还有初始化、判空和取栈顶元素等。
下面给出栈的抽象数据类型定义:
ADT Stack{
数据对象:D = {ai | ai ∈ElemSet,i = 1,2,3....n,n>=0};//ElemSet表示是一个元素集合;
据关系: R1 = {< a(i-1),ai > | a(i-1), ai ∈D,i = 1,2,3....n};//约定an端为栈顶,a1为栈底;
基本操作:
InitStack(&S);//操作结果:构造一个空栈;
DestoryStack(&S);//操作结果:栈S被销毁;
ClearStack(&S);//操作结果:栈S被清空;
StackEmpty(S);//操作结果:若栈S为空,则返回TRUE,否则FALSE。
StackLength(S);//操作结果:返回栈的元素个数,即栈的长度。
GetTop(S,&e); //操作结果:用e返回栈顶元素;
Push(&S,e); //操作结果:插入新的栈顶元素e;
Pop(&S,&e); //操作结果:删除栈顶元素,并用e返回其值;
StackTraverse(S,visit()); //操作结果:从栈底到栈顶一次对每个元素调用函数visit
}ADT Stack
3.1.2 栈的表示和实现
和线性表类型,栈也有两种存储表示方法。
顺序栈:即栈的顺序存储结构是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针top指向栈顶元素在顺序栈中的位置。通常的作法是以top = 0表示空栈,鉴于C语言中数组的下标约定从0开始,则当以C做描述语言的时候,如此会带来不便;另一方面,栈在使用过程中所需的最大空间很难估计,因此在初始化期间不应限定栈的最大容量。较合理的作法是:先为栈分配一个初始的空间大小,然后在应用过程中,当栈的空间不足时再扩大。为此可设定两个常量:STACK_INIT_SIZE和STACKINCREMENT。
顺序栈的定义:
typedef struct{
SElemType *base;
SElemType *top;
int stacksize;
}SqStack;
栈的初始化操作:
按设定的存储分配量进行第一次存储分配,base为栈底指针,若base的值为NULL,则表明栈结构不存在。称top为栈顶指针,其初值指向栈底,即top = base可作为栈空的标记,每当插入一个新的元素后指针top增1;删除栈顶元素时指针top减1;因此非空栈中的栈顶指针始终在栈顶元素的下一个位置上。
下图展示了顺序栈中数据元素和栈顶指针之间的关系;
//— — — —基本操作的算法描述— — — —
Status InitStack(SqStack &S){
//构造一个空栈S
S.base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if(!S.base)exit(OVERFLOW);
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
return OK;
}//InitStack
Status GetTop(SqStack S,SElemType &e)
{
//若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR;
if(S.top = S.base)return ERROR;
e = *(S.top - 1);
return OK;
}//GetTop
Status Push(SqStack &S,SElemType e)
{
//插入元素e为新的栈顶元素
if(S.top - S.base >= S.stacksize)
{
S.base = (SElemType *)realloc(S.base,(S.stacksize + STACKINCREMENT) * sizeof(SElemType));
if(!S.base)exit(OVERFLOW);
S.top = S.base + S.stacksize;
S.stacksize += STACKINCREMENT;
}
*S.top++ = e;
return OK;
}//Push
Status Pop(SqStack &S,SElemType &e)
{
if(S.top = S.base)return ERROR;
e = * - -S.top;
return OK;
}//Pop
栈的链式表示如下图, 由于栈的操作是线性表操作特例,则链栈的操作易于实现。