栈的定义
栈(stack)是限定在表尾进行插入和删除操作的线性表。栈又称先进后出的线性表,简称LIFO结构。
基本知识点
- 允许插入和删除的一端叫做栈顶,另一端叫做栈底
- 栈的插入操作——进栈,栈的删除操作——出栈
- 其特征为:1用数组存储。2只允许在一端进行插入和删除。 3先进后出(LIFO),最先进栈的必定最后出栈。类比于堆放一摞书,最先放在桌上的到后面一定被压在最下面,如果规定拿书只能从最上面拿的话,故只能最先放的书最后才能被拿到。
栈的顺序结构及实现
既然栈是线性表的特例,那么栈的顺序存储其实也是线性表顺序存储的简化,我们简称为顺序栈。
下面是栈的结构定义:
typedef int SElemType; //根据实际情况定义,这里定义为int型
typedef struct
{
SElemType data[MAXSIZE];
int top; //用于栈顶指针
}SqStack;
以下是进栈出栈的实现:
进栈的操作push,代码如下:
Status Push(SqStack *S,SElemType e) //插入
{
if(S->top==MAXSIZE-1)
{
return ERROR; //栈满
}
S->top++; //栈顶指针加一
S->data[S->top]=e; //将新插入元素赋值给栈顶空间
return OK;
}
栈的删除操作——出栈pop,代码如下:
Status Pop(SqStack *S,SElemType *e) //删除
{
if(S->top==-1)
{
return ERROR; //栈空
}
*e=S->data[S->top]; //将要删除的栈顶元素赋值给e*
S->top--; //栈顶指针减一
return OK;
}
两栈共享空间
其实栈的顺序存储是很方便的,只允许栈顶进出元素,在插入和删除时就不需要频繁移动元素了。但是它有一个很大的缺陷,就是必须设置足够大的数组空间,否则不够用了会很麻烦。为了解决这个问题,我们完全可以用一个数组才存储两个栈,就像两个人合租一个两室一厅的房子一样,可以最大化利用空间和降低租房成本。
像这样:
共享空间的思路为:数据元素在数组的两端,向中间靠拢,Ltop(top1)是栈1的栈顶指针,Rtop(top2)是栈1的栈底指针,只要它们指向的不是同一个位置,两个栈就可以一直使用。
下面代码献上:
typedef struct //两栈共享空间结构
{
SElemType data[MAXSIZE];
int top1;
int top2;
}SqDoubleStack;
Status Push(SqDoubleStack *S,SElemType e,int stackNumber) //插入元素e为新的栈顶元素
{
if(S->top+1==S->top2)
{
if(S->top1+1==top2) //栈满,不能插入
return ERROR;
}
if(stackNumber==1)
S->data[++S->top1]=e; //栈一进栈前+1赋值给数组元素
else if(stackNumber==2)
S->data[--S->top2]=e; //栈二进栈前-1赋值给数组元素
return OK;
}
Status Pop(SqDoubleStack *S,SElemtype *e,int stackNumber) //删除S的栈顶元素
{
if(stackNumber==1)
{
if(S->top1==-1)
return ERROR; //空栈,溢出
*e=S->data[S->top1--]; //将栈1的栈顶元素出栈
}
else if(stackNumber==2)
{
if(S->top2==MAXSIZE) //满栈,溢出
return ERROR;
*e=S->data[S->top2++]; //将栈1的栈顶元素出栈
}
return OK;
}
栈的链式存储结构及实现
栈的链式存储结构,简称为链栈。
通常对于链栈来说是不需要头结点的,像下面这张图:
对于链栈,我们也有相应的进栈和出栈操作,快来学习一下吧!
typedef struct StackNode //链栈的结构
{
SElemType data;
struct StackNode *next;
}StackNode,*LinkStackPtr;
Typedef struct LinkStack
{
LinkStackPtr top;
int count;
}LinkStack;
Status Push(LinkStack *S,SElemType e) //插入e为新的栈顶元素
{
LinkStackPtr S=(LinkStackPtr)malloc(sizeof(StackNode));
S->data=e;
S->next=S->top; //把当前栈顶元素赋值给新节点的直接后继
S->top=S;
S->count++;
return OK;
}
Status Pop(LinkStack *S,SElemType *e)
{
LinkStackPtr p;
if(StackEmpty(*S))
return ERROR;
*e=S->top->data;
p=S->top; //栈顶元素赋值为p
S->top=S->top->next; //栈顶指针后移,指向后一个结点
free(p); //释放空间
S->count--;
return OK;
}
栈的应用
栈有一个很重要的应用:在程序设计中可以实现递归的功能,例如有名的斐波那契数列的实现就可以使用栈。