栈和队列主要用于计算过程中保存的临时数据,如果数据在编程时就可以确定,那么使用几个变量就可以临时存储,但是如果存储的数据项数不能确定,就需要复杂的存储机制。这样的存储机制称为缓存。栈和队列就是使用最多的缓存结构。
我们在调用方法的时候 , 时常调用别的成员方法, 递归循环调用 , 那调用到最后,又从最后一个函数,依次返回值 , 我们熟悉这个机制.
但是我们却不知道 , 编译器是如何把这些调用信息存储起来的,用什么方法存储起来的, 这里就需要我们用到栈了,先进后出
还有生活中 , 我们往木桶里放球 ,
先放进去的后拿出来 ,我们只能在一端进行操作
还有当我们在车站的栈道里面
先进来的车 ,因为后进来的还有车 , 后进来的车堵住了去路 , 所以 后进来的车可以先出
以上的例子 , 只是生活中的一些情况 , 我们还会遇到很多类似的模型 , 那用什么来记录这些模型信息呢?
先分析元素进入的特点 , 我们只是在容器的一段进行操作 , 并且操作的总是顶端的那个元素
然后后进来的元素 ,因为离出口近 ,可以先出去
由此我们可以构建一个栈道模型 , 简称栈
操作的话, 我们只操作栈顶的元素 , 就用一个指针指栈顶元素.
所以,我们就可以定义栈的特有操作:
我们无非就是 , 定义了一个数组容器, 或者链表容器 , 然后用指针指向要操作的元素 ,就是所谓的栈顶 ,相应的栈底就是没有元素的时候 , 容器底部
元素进来 , 就把元素压入栈顶 , 指针指向栈顶 ,
元素出来 , 就把元素弹出栈顶 , 指针下移 ,移向栈顶
栈空间没有元素 , 就称作是空栈 , 就意味着不可以弹出元素
栈空间元素满了 , 就称作是满栈 , 就意味着不可以再压入元素
这就是把上述的语言描述,抽象了一下 ,作为彻底的唯物主义 , 我们还是直接上代码为妙
构建栈的顺序存储结构
用顺序表来存储栈 ,需要指向栈顶的变量,
由于顺序表是用数组来存储元素的,所以要求栈的数据元素需要同一类型 , 然后还要要固定的容量
●描述栈
°数据元素: 元素具有同一类型 (ElemType) ,最多MaxSize
°当前栈顶 : 记录栈顶的下标(栈顶指针)
typedef struct { ElemType data[MaxSize]; int top; }SqStack;
注: 这里的 top 指向的是栈顶 , 就是数组里元素的最后一个数据元素
当我们定义的数组被元素填满的时候 , 就栈满了
无元素的时候就代表 , 栈空
数组坐标是从 0开始的
下面我们开始构建顺序栈的操作条件:
●栈空条件: top = -1
栈空间有元素的时候 , 代表数组标号为 0 的位置上有元素 , top 指向数组坐标 0 的位置
,那栈空的时候 , top 就指向 -1 ,有元素的话,加一,正好变成 0
●栈满条件: top = MaxSize - 1
数组坐标从 0 开始 , 所以top 指向的数组末尾元素的位序就是 MaxSize-1
●进栈操作 top++ ; 将 新节点放在 top 处
元素进栈前, 我们的栈顶指针 top 要向上移动 ,为元素腾空间 , 然后再放元素
●退栈操作 : 从top 处取出元素 ; 然后 top --
元素要出栈 ,所以要先从 top 指引处获得元素 ,然后把 top 处的元素删除 , top 下移
初始化栈 initStack(&s)
● 建立一个新的空栈 s ,实际上是将栈顶指针指向 -1 即可
void InitStack(SqStack *&s) { s = (SqStack *)malloc(sizeof(SqStack)); s->top = -1; }
判断栈是否为空 StackEmpty(s)
●栈空的条件是 top 指向的是 -1 ,不指向 -1 就代表栈内有元素
bool StackEmpty(SqStack *s) { return(s->top == -1); }
销毁栈 ClearStack(&s)
● 释放栈 s 占用的存储空间
void DestroyStack(SqStack *&s)
{
free(s);
}
因为顺序栈,实质就是一个数组 ,我们释放数组的空间, 就相当于销毁了栈
进栈Push(&s , e)
●条件: 在栈不满时 ,可以进栈
●操作:
°将栈指针增 1
°在该位置上插入新元素 e
传入 要进的栈 , 传入要插入的元素 e
bool Push (SqStack *&s ,ElemType e){
判断栈是否满栈
if(s->top == MaxSize-1) { return false; }
如果栈不满 ,就继续进行插入操作
//栈指针top自增1 s->top++; //top指向要插入的元素 s->data[s->top] = e; //表示插入成功,返回true return true; }
出栈 Pop(&s,&e)
条件: 栈不为空
操作:
°将栈顶元素赋值给 e
°将栈指针减一
//传入出栈的指针数组 和 弹出的元素指针
bool Pop(SqStack *&s,ElemType &e)
{
//栈空的时候,栈顶指针指向 -1
if(s->top == -1)
{
//如果进入,就代表栈空,返回 false
return false;
}
//不进入上面的话,就代表栈里有元素
//把栈顶指针指向的元素,传出给指针e
e = s -> data[s->top];
//栈顶指针下移
s -> top--;
//弹出成功,返回true
return true;
}
取栈顶元素 GetTop(s , e)
●条件: 栈不为空时
●操作: 将栈顶元素赋值给 e
和出栈的操作差不多 , 只是这次我们不修改栈顶元素 ,只是将栈顶元素赋值给 e
//传入栈指针和存储取顶元素的指针
bool GetTop(SqStack *s , ElemType &e)
{
//如果栈空,则返回false,无元素不可取元素
if(s->top == -1)
{
return false;
}
//如果栈不空,则把栈顶元素传入取元素的指针e
e = s -> data[s->top];
return true;
}