一、栈的定义
栈是一种只能在一端进行插入或删除操作的线性表。
表中允许进行插入、删除操作的一端称为栈顶。表的另一端称为栈底。
栈顶的当前位置是动态的,栈顶的当前位置由一个称为栈顶指针的位置指示器指示。
当栈中没有数据元素时,称为空栈。
栈的插入操作通常称为进栈或入栈,栈的删除操作通常称为退栈或出栈。
栈的主要特点是“后进先出”,即后进栈的元素先出栈。栈也称为后进先出表。
栈的几种基本运算如下:
InitStack(&s):初始化栈。构造一个空栈s。
DestroyStack(&s):销毁栈。释放栈s占用的存储空间。
StackEmpty(s):判断栈是否为空:若栈s为空,则返回真;否则返回假。
Push(&S,e):进栈。将元素e插入到栈s中作为栈顶元素。
Pop(&s,&e):出栈。从栈s中退出栈顶元素,并将其值赋给e。
GetTop(s,&e):取栈顶元素。返回当前的栈顶元素,并将其值赋给e。
二、栈的顺序存储结构及其基本运算实现
假设栈的元素个数最大不超过正整数MaxSize,所有的元素都具有同一数据类型ElemType
则可用下列方式来定义栈类型SqStack:
typedef struct{ ElemType data[MaxSize];
int top; //栈顶指针
} SqStack;
顺序栈4要素:
栈空条件:top=-1
栈满条件:top=MaxSize-1
进栈e操作:top++; 将e放在top处
退栈操作:从top处取出元素e; top--;
(1)初始化栈initStack(&s)
建立一个新的空栈s,实际上是将栈顶指针指向-1即可。对应算法如下:
void InitStack(SqStack *&s){ s=(SqStack *)malloc(sizeof(SqStack));
s->top=-1;
}
(2)销毁栈ClearStack(&s)
释放栈s占用的存储空间。对应算法如下:
void DestroyStack(SqStack *&s)
{
free(s);
}
(4)进栈Push(&s,e)
在栈不满的条件下,先将栈指针增1,然后在该位置上插入元素e。对应算法如下:
bool Push(SqStack *&s,ElemType e)
{
if (s->top==MaxSize-1) //栈满的情况,即栈上溢出
return false;
s->top++; //栈顶指针增1
s->data[s->top]=e; //元素e放在栈顶指针处
return true;
}
(5)出栈Pop(&s,&e)
在栈不为空的条件下,先将栈顶元素赋给e,然后将栈指针减1。对应算法如下:
bool Pop(SqStack *&s,ElemType &e)
{
if (s->top==-1) //栈为空的情况,即栈下溢出
return false;
e=s->data[s->top]; //取栈顶指针元素的元素
s->top--; //栈顶指针减1
return true;
}
(6)取栈顶元素GetTop(s)
在栈不为空的条件下,将栈顶元素赋给e。对应算法如下:
bool GetTop(SqStack *s,ElemType &e)
{
if (s->top==-1) //栈为空的情况,即栈下溢出
return false;
e=s->data[s->top]; //取栈顶指针元素的元素
return true;
}
三、栈的链式存储结构及其基本运算的实现
采用链式存储的栈称为链栈,这里采用单链表实现。
链栈的优点是不存在栈满上溢的情况。这里规定栈的所有操作都是在单链表的表头进行的,用带头节点的单链表表示链栈,第一个数据节点是栈顶节点,最后一个节点是栈底节点,栈中元素自栈顶到栈底依次是a1、a2、…、an。
链栈的4要素:
栈空条件:s->next=NULL
栈满条件:不考虑
进栈e操作:将包含e的节点插入到头节点之后
退栈操作:取出头节点之后节点的元素并删除之
链栈中数据节点的类型LiStack定义如下:
typedef struct linknode
{ ElemType data; //数据域
struct linknode *next; //指针域
} LiStack;
链栈和链表很类似,只是在进栈和出栈时略有不同:
(1)进栈Push(&s,e)
将新数据节点插入到头节点之后。对应算法如下:
void Push(LiStack *&s,ElemType e)
{ LiStack *p;
p=(LiStack *)malloc(sizeof(LiStack));
p->data=e; //新建元素e对应的节点*p
p->next=s->next; //插入*p节点作为开始节点
s->next=p;
}
(2)出栈Pop(&s,&e)
在栈不为空的条件下,将头节点后继数据节点的数据域赋给e,然后将其删除。对应算法如下:
bool Pop(LiStack *&s,ElemType &e)
{ LiStack *p;
if (s->next==NULL) //栈空的情况
return false;
p=s->next; //p指向开始节点
e=p->data;
s->next=p->next; //删除*p节点
free(p); //释放*p节点
return true;
}