栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
首先系统或者数据结构栈中数据内容的读取与插入(压入push和 弹出pop)是两回事!插入是增加数据,弹出是删除数据 ,这些操作只能从栈顶即最低地址作为约束的接口界面入手操作 ,但读取栈中的数据是随便的没有接口约束之说。很多人都误解这个理念从而对栈产生困惑。而系统栈在计算机体系结构中又起到一个跨部件交互的媒介区域的作用 即 cpu 与内存的交流通道 ,cpu只从系统给我们自己编写的应用程序所规定的栈入口线性地读取执行指令, 用一个形象的词来形容它就是pipeline(管道线、流水线)。
定义:栈是限定仅在表头进行插入和删除操作的线性表。要搞清楚这个概念,首先要明白”栈“原来的意思,如此才能把握本质。"栈“者,存储货物或供旅客住宿的地方,可引申为仓库、中转站,所以引入到计算机领域里,就是指数据暂时存储的地方,所以才有进栈、出栈的说法。
栈顶(Top):允许进行插入、删除操作的一端,又称为表尾。用栈顶指针(top)来指示栈顶元素。
栈底(Bottom):是固定端,又称为表头。
空栈:当表中没有元素时称为空栈。
设栈S=(a1,a2,…an),则a1称为栈底元素,an为栈顶元素,如图3-1所示。
栈中元素按a1,a2,…an的次序进栈,退栈的第一个元素应为栈顶元素。即栈的修改是按后进先出的原则进行的。
栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针。
栈是允许在同一端进行插入和删除操作的特殊线性表。允许进行插入和删除操作的一端称为栈顶(top),另一端为栈底(bottom);栈底固定,而栈顶浮动;栈中元素个数为零时称为空栈。插入一般称为进栈(PUSH),删除则称为退栈(POP)。栈也称为后进先出表。
为什么要用栈?
有人可能会觉得,用数组或链表直接实现功能不就行了吗?干吗要引入栈这样的数据结构呢?
其实这和我们明明有两只脚可以走路,干吗还要乘汽车、火车、飞机一样。理论上,陆地上的任何地方,你都是可以靠双脚走到的,可那需要多少时间和精力呢?我们更关注的是到达而不是如何去的过程。栈的引入简化了程序设计的问题,划分了不同关注层次,使得思考范围缩小,更加聚焦于我们要解决的问题核心。反之,像数组等,因为要分散精力去考虑数组的下标增减等细节问题,反而掩盖了问题的本质。所以现在的许多高级语言,比如Java、C#等都有对栈结构的封装,你可以不用关注它的实现细节,就可以直接使用Stack的push和pop方法,非常方便。
栈的抽象数据类型定义
ADT Stack{
数据对象:D ={ ai|ai∈ElemSet, i=1,2,…,n,n≥0 }
数据关系:R ={
基本操作:初始化、进栈、出栈、取栈顶元素等
} ADT Stack
栈的顺序存储结构简称为顺序栈,和线性表相类似,用一维数组来存储栈。根据数组是否可以根据需要增大,又可分为静态顺序栈和动态顺序栈。
◆ 静态顺序栈实现简单,但不能根据需要增大栈的存储空间;
◆ 动态顺序栈可以根据需要增大栈的存储空间,但实现稍为复杂。
采用动态一维数组来存储栈。所谓动态,指的是栈的大小可以根据需要增加。
◆ 用bottom表示栈底指针,栈底固定不变的;栈顶则随着进栈和退栈操作而变化。用top(称为栈顶指针)指示当前栈顶位置。
◆ 用top=bottom作为栈空的标记,每次top指向栈顶数组中的下一个存储位置。
◆ 结点进栈:首先将数据元素保存到栈顶(top所指的当前位置),然后执行top加1,使top指向栈顶的下一个存储位置;
栈的类型定义
#define STACK_SIZE 100 /* 栈初始向量大小 */
#define STACKINCREMENT 10 /* 存储空间分配增量 */
#typedef int ElemType ;
typedef struct sqstack
{
ElemType *bottom; /* 栈不存在时值为NULL */
ElemType *top; /* 栈顶指针 */
int stacksize ; /* 当前已分配空间,以元素为单位 */
}SqStack ;
栈的初始化
Status Init_Stack(void)
{ SqStack S ;
S.bottom=(ElemType *)malloc(STACK_SIZE *sizeof(ElemType));
if (! S.bottom) return ERROR;
S.top=S.bottom ; /* 栈空时栈顶和栈底指针相同 */
S. stacksize=STACK_SIZE;
return OK ;
}
压栈(元素进栈)
Status push(SqStack S , ElemType e)
{
if (S.top-S.bottom>=S. stacksize-1)
{
S.bottom=(ElemType *)realloc((S. STACKINCREMENT+STACK_SIZE) *sizeof(ElemType)); /* 栈满,追加存储空间 */
if (! S.bottom) return ERROR;
S.top=S.bottom+S. stacksize ;
S. stacksize+=STACKINCREMENT ;
}
*S.top=e; S.top++ ; /* 栈顶指针加1,e成为新的栈顶 */
return OK;
}
弹栈(元素出栈)
Status pop( SqStack S, ElemType *e )
/*弹出栈顶元素*/
{
if ( S.top== S.bottom )
return ERROR ; /* 栈空,返回失败标志 */
S.top-- ; e=*S. top ;
return OK ;
}
当栈满时做进栈运算必定产生空间溢出,简称“上溢”。上溢是一种出错状态,应设法避免。
当栈空时做退栈运算也将产生溢出,简称“下溢”。下溢则可能是正常现象,因为栈在使用时,其初态或终态都是空栈,所以下溢常用来作为控制转移的条件。
typedef int SElemType;
typedef int ElemType;
typedef int Status;
#define STACK_INIT_SIZE 100 // 存储空间初始分配量
#define STACKINCREMENT 10 // 存储空间分配增量
// 描述顺序栈的存储结构有两种格式:
//----------- 栈的动态分配存储结构 ------------
typedef struct
{
SElemType *base; // 在栈构造之前和销毁之后,base的值为NULL
SElemType *top; // 栈顶指针
int stacksize; // 当前已分配的存储空间,以元素为单位
} SqStack; // 顺序栈
//-------- 栈的静态分配存储结构 ----------
#define MAXSIZE 100 // 预定义栈中存储单元总个数
typedef struct {
ElemType data[MAXSIZE]; // 栈(连续空间)
int top; // 栈顶指针(实际是数组的下标值)
} SqStack;
// 算法的实现 - 栈的动态分配存储结构
Status InitStack(SqStack &S)
{ // 构造一个空栈S
if(!(S.base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType))))
exit(OVERFLOW); // 存储分配失败
S.top=S.base;
S.stacksize=STACK_INIT_SIZE;
return OK;
}
Status DestroyStack(SqStack &S)
{ // 销毁栈S,S不再存在
free(S.base);
S.base=NULL;
S.top=NULL;
S.stacksize=0;
return OK;
}
Status ClearStack(SqStack &S)
{ // 把S置为空栈
S.top=S.base;
return OK;
}
Status StackEmpty(SqStack S)
{ // 若栈S为空栈,则返回TRUE,否则返回FALSE
if(S.top==S.base)
return TRUE;
else
return FALSE;
}
int StackLength(SqStack S)
{ // 返回S的元素个数,即栈的长度
return S.top-S.base;
}
Status GetTop(SqStack S,SElemType &e)
{ // 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
if(S.top>S.base)
{
e=*(S.top-1);
return OK;
}
else
return ERROR;
}
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;
}
Status Pop(SqStack &S,SElemType &e)
{ // 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
if(S.top==S.base)
return ERROR;
e=*--S.top;
return OK;
}
应用1:对于输入的任意一个非负十进制整数,打印输出与其等值的八进制数
typedef int SElemType;
typedef int ElemType;
typedef int Status;
#define OVERFLOW 1
#define OK 1
#define TRUE 1
#define FALSE 0
#define ERROR 1
#define STACK_INIT_SIZE 100 // 存储空间初始分配量
#define STACKINCREMENT 10 // 存储空间分配增量
// 描述顺序栈的存储结构有两种格式:
//----------- 栈的动态分配存储结构 ------------
typedef struct
{
SElemType *base; // 在栈构造之前和销毁之后,base的值为NULL
SElemType *top; // 栈顶指针
int stacksize; // 当前已分配的存储空间,以元素为单位
} SqStack; // 顺序栈
#include
#include
void conversion();
int main()
{
conversion();
}
/*
//-------- 栈的静态分配存储结构 ----------
#define MAXSIZE 100 // 预定义栈中存储单元总个数
typedef struct {
ElemType data[MAXSIZE]; // 栈(连续空间)
int top; // 栈顶指针(实际是数组的下标值)
} SqStack;
*/
// 算法的实现 - 栈的动态分配存储结构
Status InitStack(SqStack &S)
{ // 构造一个空栈S
if(!(S.base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType))))
exit(OVERFLOW); // 存储分配失败
S.top=S.base;
S.stacksize=STACK_INIT_SIZE;
return OK;
}
Status DestroyStack(SqStack &S)
{ // 销毁栈S,S不再存在
free(S.base);
S.base=NULL;
S.top=NULL;
S.stacksize=0;
return OK;
}
Status ClearStack(SqStack &S)
{ // 把S置为空栈
S.top=S.base;
return OK;
}
Status StackEmpty(SqStack S)
{ // 若栈S为空栈,则返回TRUE,否则返回FALSE
if(S.top==S.base)
return TRUE;
else
return FALSE;
}
int StackLength(SqStack S)
{ // 返回S的元素个数,即栈的长度
return S.top-S.base;
}
Status GetTop(SqStack S,SElemType &e)
{ // 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
if(S.top>S.base)
{
e=*(S.top-1);
return OK;
}
else
return ERROR;
}
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;
}
Status Pop(SqStack &S,SElemType &e)
{ // 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
if(S.top==S.base)
return ERROR;
e=*--S.top;
return OK;
}
// +++++++++++++++++++++++++++++++++++
void conversion()
{ // 对于输入的任意一个非负十进制整数,打印输出与其等值的八进制数
SqStack s;
unsigned n; // 非负整数
SElemType e;
InitStack(s); // 初始化栈
printf("n{>=0}=");
scanf("%u",&n); // 输入非负十进制整数n
while(n) // 当n不等于0
{
Push(s,n%8); // 入栈n除以8的余数(8进制的低位)
n=n/8;
}
while(!StackEmpty(s)) // 当栈不空
{
Pop(s,e); // 弹出栈顶元素且赋值给e
printf("%d",e); // 输出e
}
printf("\n");
}
应用2:括号匹配
typedef char SElemType;
typedef int ElemType;
typedef int Status;
#define OVERFLOW 1
#define OK 1
#define TRUE 1
#define FALSE 0
#define ERROR 1
#define STACK_INIT_SIZE 100 // 存储空间初始分配量
#define STACKINCREMENT 10 // 存储空间分配增量
// 描述顺序栈的存储结构有两种格式:
//----------- 栈的动态分配存储结构 ------------
typedef struct
{
SElemType *base; // 在栈构造之前和销毁之后,base的值为NULL
SElemType *top; // 栈顶指针
int stacksize; // 当前已分配的存储空间,以元素为单位
} SqStack; // 顺序栈
#include
#include
void conversion();
/*
//-------- 栈的静态分配存储结构 ----------
#define MAXSIZE 100 // 预定义栈中存储单元总个数
typedef struct
{
ElemType data[MAXSIZE]; // 栈(连续空间)
int top; // 栈顶指针(实际是数组的下标值)
} SqStack;
*/
// 算法的实现 - 栈的动态分配存储结构
Status InitStack(SqStack &S)
{ // 构造一个空栈S
if(!(S.base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType))))
exit(OVERFLOW); // 存储分配失败
S.top=S.base;
S.stacksize=STACK_INIT_SIZE;
return OK;
}
Status DestroyStack(SqStack &S)
{ // 销毁栈S,S不再存在
free(S.base);
S.base=NULL;
S.top=NULL;
S.stacksize=0;
return OK;
}
Status ClearStack(SqStack &S)
{ // 把S置为空栈
S.top=S.base;
return OK;
}
Status StackEmpty(SqStack S)
{ // 若栈S为空栈,则返回TRUE,否则返回FALSE
if(S.top==S.base)
return TRUE;
else
return FALSE;
}
int StackLength(SqStack S)
{ // 返回S的元素个数,即栈的长度
return S.top-S.base;
}
Status GetTop(SqStack S,SElemType &e)
{ // 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
if(S.top>S.base)
{
e=*(S.top-1);
return OK;
}
else
return ERROR;
}
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;
}
Status Pop(SqStack &S,SElemType &e)
{ // 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
if(S.top==S.base)
return ERROR;
e=*--S.top;
return OK;
}
// 括号匹配的检验,(限于()、[])
void check()
{ // 对于输入的任意一个字符串,检验括号是否配对
SqStack s;
SElemType ch[80],*p,e;
if(InitStack(s)) // 初始化栈成功
{
printf("请输入表达式\n");
gets(ch);
p=ch;
while(*p) // 没到串尾
switch(*p)
{
case '(':
case '[':Push(s,*p++);
break; // 左括号入栈,且p++
case ')':
case ']':if(!StackEmpty(s)) // 栈不空
{
Pop(s,e); // 弹出栈顶元素
if(*p==')'&&e!='('||*p==']'&&e!='[') // 弹出的栈顶元素与*p不配对
{
printf("左右括号不配对\n");
exit(ERROR);
}
else
{
p++;
break; // 跳出switch语句
}
}
else // 栈空
{
printf("缺乏左括号\n");
exit(ERROR);
}
default: p++; // 其它字符不处理,指针向后移
}
if(StackEmpty(s)) // 字符串结束时栈空
printf("括号匹配\n");
else
printf("缺乏右括号\n");
}
}
int main()
{
check();
return 0;
}