栈的定义
栈也称为堆栈,它是限定仅在表尾进行插入和删除操作的线性表。对于栈来说,表尾称为栈顶,表头称为栈尾。栈顶是动态变化的,它由一个栈指针的变量指示的。当表中没有元素时,称为空栈。栈的插入操作称为入栈或进栈,而删除操作称为出栈或退栈。
栈是一种后进先出的数据结构,也就是说最先进栈的一定是栈底元素,最后进栈的一定是栈顶元素,而每次删除的元素也一定是栈顶元素。
栈的抽象数据类型的定义:
ADT Stack{
数据对象;
数据关系;
基本操作:
InitStack(&S)
操作结果:构造一个空栈S
DestroyStack(&S)
初始条件:存在栈S
操作结果:栈S被销毁
ClaerStack(&S)
初始条件:存在栈S
操作结果:将S清为空栈
StackEmpty(S)
初始条件:存在栈S
操作结果:若栈S为空栈,则返回TRUE,否则返回FALSE
StackLength(S)
初始条件:存在栈S
操作结果:返回S的元素个数,即栈的长度
GetTop(S,&e)
初始条件:存在栈S
操作结果:用e返回S的栈顶元素
Push(&S,&e)
初始条件:存在栈S
操作结果:插入元素e为新的栈顶元素
Pop(&S,&e)
初始条件:存在栈S且非空
操作结果:删除S的栈顶元素,并用e返回其值
StackTraver(S,visit())
初始条件:存在栈S且非空
操作结果:从栈底到栈顶依次对S的每个数据元素调用函数visit()。一旦调用失
败,则操作失效
}ADT Stack
栈的表示与实现
1.宏定义解释
#define STACK_INIT_SIZE 100 //存储空间初始分配量
#define STACKINCREMENT 10 //存储空间分配增量
2.结构类型
typedef struct{
SElemType *base; //栈底的指针
SElemType *top; //栈顶的指针
int stacksize; //当前分配的存储空间
}SqStack;
3.基本操作的实现
(1)初始化栈InitStack
Status InitStack(SqStack &S){
S.base=(SElemType*)malloc(STACK_INIT_SIZE*sizeof(SElemType)) //为栈底申请空间
if(!S.base){
exit(OVERFLOW); //分配失败
}
S.top = S.base; //初始化时栈顶指向栈底
S.stcaksize = STACK_INIT_SIZE;
return OK;
}
(2)销毁栈DestroyStack
Status DestroyStack(SqStack &S)
{
S.top = NULL; //栈顶指针指向空
S.stacksize = 0; //栈的内存置为0
free(S.base); //释放栈底的指针
return OK;
}
(3)清空栈ClearStack
Status ClearStack(SqStack &S)
{
S.top = S.base; //当栈顶=栈底时为空栈
return OK;
}
(4)判断栈是否为空StackEmpty
Status StackEmpty(SqStack S)
{
if (S.top == S.base) //当栈顶=栈底时为空栈
return TRUE; //空栈则返回TRUE
else
return FALSE;
}
(5)求栈的长度StackLength
Status StackLength(SqStack S)
{
if (S.top == S.base)
return FALSE;
else
return (S.top - S.base);//直接相减就是栈的长度
}
(6)求栈顶元素GetTop
Status GetTop(SqStack S, SElemType &e)
{
if (S.top == S.base)
return FALSE;
else
e = *(S.top - 1); //返回栈顶的值
return e;
}
(7)栈顶插入元素Push
Status Push(Sqstack &S,SElemType e){
if(S.top-S.base>=S.stacksize){ //如果超出初始的容量则要申请内存
S.base = (ElemType *)realloc(S.base, (S.stacksize + STACKINCREMENT) * sizeof(ElemType));
if(!S.base){
exit(OVERFLOW);
}
S.stop = S.base + S.stacksize; //栈顶的指向
S.stacksize += STACKINCREMENT; //容量增加
}
*S.stop=e;
S.top++;
return OK;
}
(8)删除栈顶元素Pop
Status Pop(SqStack &S,SElemType &e){
if(S.top==S.base){
return ERROR;
}
else{
S.top--; //top指向栈顶的元素
e=*S.top; //给e赋值为栈顶元素的值
return e;
}
}
(9)遍历栈StackTraverse
Status StackTraverse(SqStack S){
if(S.base==NULL||S.top==S.base){
return ERROR;
}
ElemType *p;
p=S.top;
while (p > S.base)
{
p--;
printf("%d ",*p);
}
return OK;
}
栈与递归
递归是指在函数的定义中,在定义自己的同时又出现了对自身的调用。而栈的后进先出的思想可以很好地应用于递归当中。
在递归中最经典的问题就是n阶汉诺塔问题,即假设有三个塔X,Y,Z,在塔X上放置n个大小直径各不相同且从小到大为1、2……n的圆盘,要求将塔X上的n个圆盘移动到塔Z上并要求按照同样的叠放顺序排列,同时必须满足:1)每次只能移动一个圆盘。2)圆盘可以放置X,Y,Z中任何一个塔上。3)小盘必须放在大盘的上面。
算法实现:
void Hanoi(int n,char x,char y,char z){
//将塔X上排列好的由上到下编号为1~n的圆盘移动到塔Z上,Y作为辅助塔
if(n==1){
Move(x,1,z); //函数功能:将编号为1的圆盘从X移到Z上
}
else{
Hanoi(n-1,x,z,y); //调用自己
Move(x,n,z);
Hanoi(n-1,y,x,z);
}
}