什么是栈
乍一听栈,似乎脑中会浮现出一座客栈,或是一个栈桥的样子,这条栈桥又窄又长,无数的同学在路过的时候都失足跌落…
好啦,不开玩笑了。前面我们学过了顺序表,也学习了链表,如今的栈只是基于这两种数据结构的应用而已,不过在我看来,栈还真的像一座窄桥,你不过,我不过,我不出,你也别想出.
言归正传,什么是栈呢?从生活实际中获取实例是理解的最好方式,那么生活中哪里应用到了栈呢?
栈的定义
咱先不谈定义,谈谈实例。
在我们使用浏览器浏览新闻的时候,突然发现,一则广告,wow! XXX代言,下载就能十连抽,不爆sss不开局!点进去一看,这骗的太没有诚意了,这明星图片都给p虚了,这时候如果我们要拂袖而去,怎么办呢?如果是跳转的页面那我们点击回退按钮就行了,对吧。
这个回退按钮其实就是浏览器在内存上应用的一种栈的存储结构,就像我们使用的word或画图中的撤销,我们撤销是一步步的回退,从当前的操作一步步移动到以前的。又比如自动手枪中的子弹,我们依次射击出去,最后放入的子弹反而第一个射出,这些先进后出的情况其实都是栈在实际中的应用。
下面我们来看一下栈的定义吧
取自百度百科
栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
划重点!运算受限 线性表 表尾插入 表头删除 插入是入栈 删除叫出栈
我们一般把允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈叫做空栈,栈又称为先进后出(Last In First Out)的线性表,简称LIFO结构,下次见到可不要被唬到了,当时我第一眼看到在想:高级!了解后:原来不过如此…所以术语也要了解,这样咱们就可以拿它去糊别人了…
- 首先要明确栈是一种线性表
- 线性表有两种:顺序表 链表 栈同样如此
顺序栈
顺序栈类型描述
#define MaxSize 100//顺序栈的最大元素数
typedef struct{
int elem[MaxSize];
int top;//栈顶指针,其实就是数组下标
}SeqStack;
创建空栈
SeqStack *InitStack(){
SeqStack *s;
s = (SeqStack*)malloc(sizeof(SeqStack));
s->top = -1;//空栈栈顶指针为-1 判断是否为空栈据此即可
return s;
}
入栈
int Push(SeqStack *s , int x){
//先判断是否栈满
if(s->top == MaxSize - 1){
printf("栈已满");
return 0;
}
//如果栈不满则进栈
else{
s->top++;
s->elem[s->top] = x;
return 1;
}
}
出栈
int Pop(SeqStack *s , int *x){
//x是用来存储删除的内容的
//栈空不能出栈
if(s->top == -1){
printf("栈已满");
return 0;
}
else{
*x = s->elem[s->top];
s->top--;
return 1;
}
}
栈的存储空间有限,如果我们开辟两个栈空间,有时候我们会发现,第一个栈空间已经用完,可能第二个空间还只有一两个元素,因此,我们可以从栈的表头,表尾同时进行两个栈的存储
因为需要两个指针,所以栈的结构也要发生一定的变化
我们需要两个栈的指针,我们还需要判断是存储进表1还是表2
#define MaxSize 100
typedef struct{
int elem[MaxSiz e];
int leftTop;
int rightTop;
}SeqStack;
int InitStack(SeqStack *s){
s = (SeqStack*)malloc(sizeof(SeqStack));
if(s == NULL){
printf("空间创建失败");
return 0;
}
else{
s->LeftTop = -1;
s->rightTop = MaxSize;
return 1;
}
}
//入栈函数
int PushStack(SeqStack *s,int judge,int x){
//judge是判断存入表1还是表2
if(s->leftTop + 1==s->rightTop){
printf("栈已满");
return 0;
}
if(judge ==0){
s->leftTop++;
s->[leftTop] = x;
return 1;
}
else if(judge ==1){
s->rightTop--;
s->[rightTop] = x;
return 1;
}
else{
printf("参数错误");
return 0;
}
}
//出栈函数
int PopStack(SeqStack *s,int judge , int *x){
//判断是否栈空
if(judge == 0){
if(s->leftTop == -1){
printf("栈空,无可出栈数据");
return 0;
}
else{
*x = s->elem[leftTop];
s->leftTop--;
return 1;
}
}
else if(judge == 1){
if(s->rightTop == -1){
printf("栈空,无可出栈数据");
return 0;
}
else{
*x = s->elem[rightTop];
s->rightTop++;
return 1;
}
}
else{
printf("参数错误");
return 0;
}
}
关于上面的x,只是用来存储删除的数据,可有可无,但习惯性的保存删除的数据,便于检查,也是一种代码规范
链栈
链栈就是通过链表实现存储的栈,整体的实现与顺序栈基本一致,我们就直接实现链栈的共享空间代码
//为了方便存放链表指针,我们把指针放在一个指针数组中
#define MaxSize 100
StackNode *top[MaxSize];
typedef struct StackNode{
int data;
StackNode *next;
}StackNode;
//入栈操作
//采用头插法
int PushStack(StackNode *top[i] , int x){
StackNode *p;
p = (StackNode*)malloc(sizeof(StackNode));
if(p == NULL){
printf("分配内存失败");
return 0;
}
p->next = top[i]->next;
top[i]->next = p;
return 1;
}
//出栈操作
int PopStack(StackNode *top[i] , int *x){
StackNOde *p;
if(top[i]->next == NULL){
printf("空栈,无可删除数据");
return 0;
}
else{
p = top[i]->next;
top[i]->next = p-next;
x = p->data;
free(p);
return 1;
}
}
这就是栈的基本操作了,是不是觉得对栈有一定的了解了呢,学完了基本的知识点,下一步就让我们去找实例去实践一下吧。