栈是限定仅在表尾进行插入的删除操作的线性表
我们把允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何 数据元素的栈称为空栈。栈又称为后进先出的线性表,简称LIFO结构。
注意:
栈是一个线性表,也就是说栈元素具有线性关系,即前驱后继关系。
栈的特殊之处在于限制了这个线性表的插入和删除位置,它始终在栈顶进行。这也就使得:栈底是固定的,最先进栈的只能在栈底。
栈的插入操作,叫作进栈,也称压栈、入栈。
栈的删除操作,叫作出栈,也称弹栈。
栈的引用简化了程序设计的问题,划分了不同关注层次,使得思考范围缩小,更加聚焦于我们要解决问题的核心。
牢记一点,栈是后进先出的。
打个比方:1,2,3按顺序进栈,那么合理的出栈顺序有很多种
比如:3,2,1或者1,2,3或者2,1,3或者1,3,2或者2,3,1
但是像3,1,2这种出栈顺序就不可能,因为如果3先出栈,那么意味这1,2已经入栈,那么2就一定要比1先出栈。
这让我想起我之前做了一个判断出栈的合法顺序的题目;
例题:输入n,和一个序列,代表需要判断的出栈顺序,如果合理输出yes,不合理输出no
样例:
输入:3 输出:yes
3 2 1
#include
int main()
{
int n,i,j,a[100],b[100];
while(~scanf("%d",&n))
{
if(n==0)break;
int top=0,di=0,k=0;
for(i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
for(i=1; i<=n; i++)
{
for(j=di+1; j<=a[i]; j++)
{
di=j;
b[top++]=j;//入栈
}
if(b[--top]!=a[i])//出栈并比较
k++;
}
if(k>0)printf("No\n");
else printf("Yes\n");
}
return 0;
}
栈的顺序存储结构是线性表顺序存储的简化,简称为顺序栈。用数组来实现。
定义top来表示栈顶元素在数组中的位置,top初始值为-1,当栈中有一个元素时top=0;
//入栈
void push(int *s,int a)//a为要入栈的元素
{
if(s->top==max-1)//栈满时
return error;
s->top++;//栈顶指针加一
s->date[s->top]=a;//入栈
return OK;
}
//出栈
void pop(int *s,int a)//用a来接收要出栈的元素
{
if(s->top==-1)//栈空时
return error;
a=s->date[s->top];//将要出栈的元素赋给a
s->top--;//栈顶指针减一
return OK;
}
当两个具有相同数据类型的栈,我们可以考虑让两栈共享一个空间。
只需要让top1指向数组的始端,让top2指向数组的终端,然后向中间靠拢,当top1+1=top2时栈满。
用链表来实现栈,此时栈顶指针其实就是链表的头指针,将栈顶放在链表的头部。
对于链栈来说,基本不存在栈满的情况,除非内存已经没有使用空间。空栈时即为top=NULL时。
链栈的操作与绝大部分的单链表类似,只是在插入和删除上特殊一点。
//入栈
void push(Linklist *S,int a)
{
Linklistptr s=(Linklistptr)malloc(sizeof(node));
s->date=a;
s->next=S->top;
S->top=s;
S->count++;
return ok;
}
//出栈
void pop(Linklist *S,int a)
{
Lintklistptr p;
if(stsckempty(*S))
return error;
a=S->top->date;
p=S->top;
S->top=S->top->next;
free(p);
S->count--;
return ok;
}
如果栈的输赢过程中元素变化不可预料,有时很小,有时非常大,那么最好是用链栈,反之,如果它的变化在可控范围内,建议使用顺序栈会更好一点。