栈也是一种特殊的线性表,但不同的是,栈的操作与传统的线性表不同。传统的线性表可以完成随机位置存取,而栈的结构决定了它进行操作的特点:仅仅在表尾进行插入或删除操作(后进先出)。表尾端称作栈顶,而与之相对的,表头端称作栈底。可以将栈的结构与子弹弹夹进行类比,后压入的子弹先被发射,正如栈的后进先出特点一般。
假设栈中的元素如下所示:,若设置
作为栈底元素,与之相对的
则作为栈顶的元素,
是最后一个被压入栈的,同时也会是第一个出栈的。元素输入栈的顺序与输出栈的顺序直接相反。栈的结构示意图如下:
![](https://i-blog.csdnimg.cn/blog_migrate/c74104f297a30913ec612a9d2277bfa6.jpeg)
栈的顺序表示基本结构如下,要求利用一组地址连续的内存单元来存储信息,元素的数据按顺序由栈底依次存储到栈顶,再由栈顶开始依次向下取出或添加元素 。在栈的顺序表示之中,先定义栈的类名为SqStack,需要设置名为base与top的两个指针,分别指示栈底的内存与栈顶的内存,同时定义int类型的变量用于设置栈的内存。代码如下:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#define size 1000
#define incresize 10
using namespace std;
typedef struct
{
int *base;
int *top;
int stacksize;
}SqStack;
在定义了栈的基本结构后,按照设定的分配量size分配结点指针所指的内存的空间,base名为栈底指针,指向栈底部元素的内存。top名为栈顶指针,初始化与base指针指向相同,栈的内存设置为size变量。插入与删除元素之时,仅仅需要移动栈顶指针即可。由栈的指针的结构可以看出,非空栈的栈顶指针始终指向的是栈顶元素的上一个位置,这与顺序表插入节点的操作也是类似的。顺序栈的结构初始化代码如下:
void Init(SqStack s)
{
s.base=(int *)malloc(size*sizeof(int));
s.top=s.base;
s.stacksize=size;
}
栈进行了初始化操作后,开始定义三个基本操作,分别是入栈,出栈以及获取栈顶元素。入栈操作主要思路如下:1)先进行内存是否溢出的判别,由于栈所占用的内存是连续一片内存,所以,当栈顶指针减去栈底指针的数值差大于栈的设置长度时,需要重新定义栈底指针(base)所指的内存的大小 2)进行判别完毕后,重置top指针指向的内存 3)将元素e入栈,具体操作为栈顶指针top上移一位,指针所指的内存赋值为e(返回值为e)。具体代码如下:
void push(SqStack s,int e)
{
if(s.top-s.base>s.stacksize)
{
s.base=(int*)realloc(s.base,(s.stacksize+incresize)*sizeof(int));
s.top=s.base+s.stacksize;
s.stacksize+=incresize;
}
*s.top++=e;
}
与入栈操作相反地,出栈操作不需要进行内存的判别,只需要先将栈顶指针下移,接着用int类型的变量e返回栈顶元素的值即可。具体代码如下:
void pop(SqStack s,int e)
{
if(s.top!=s.base)
{
e=*(--s.top);
}
cout<<e<<endl;
}
根据栈的结构,不难得出获得栈顶元素的具体操作 :仅仅只需要访问栈顶指针所指内存的下一个单位内存,并用int 类型的变量e返回该指针所指内存的数据域。 具体代码如下:
void GetTop(SqStack s,int e)
{
if(s.top!=s.base)
{
e=*(s.top-1);
cout<<e<<endl;
}
}