数据结构的三要素-- 逻辑结构、数据的运算、存储结构(物理结构)
栈
我们先复习一下线性表,线性表就是 具有相同的数据类型的n(n>=0)个数据元素的有限队列,其中n为表长.
栈(Stack):是一种特殊的线性表,只允许在一端进行插入和删除操作的线性表,就和我们的羊肉串一样,串的时候,第一个羊肉垫底,吃的时候最后一个穿入的肉肉第一个被吃。
术语
栈顶,栈底,空栈。

- 栈顶 允许插入和删除的一端
- 栈底 :禁止插入和删除的一端
- 空栈:没有数据元素的栈
栈的特点 : LIFO, Last In First Out 先进后出
栈的基本操作
InitStack(&S)
初始化一个空栈DestroyStack(&S)
销毁一个栈ClearStack(&S)
清空一个栈Emptystack(S)
判断栈是否为空GetTop(S)
获取栈顶数据Push(&S,e)
将e推入栈中,作为新的栈顶Pop(&S,&e)
推出S的栈顶元素,并用e返回
其中出栈 Pop和入栈在Push是栈的核心操作。
分析采用如何存储结构
当然栈作为逻辑结构实现它有两中方法,顺序栈和链式存储.
通过以上,我们可以得知,栈经常操作的栈的栈顶元素,没有在其他位置插入和删除元素,并没有体现出链式存储结构的优势,所以顺序表是非常适合的存储结构。当然在没有限制使用连续的空间下,个人认为顺序存储结构是一个不错的选择,所以本篇探讨如何 使用顺序存储结构实现 栈。
由于栈的操作没有链表的操作多,显然实现起来就简单许多。
判断多少种合法出栈顺序问题
题目:如果入栈顺序为 A ,B,C, D,那么出栈顺序可能为 A D C B 吗
解题, 假设A,进栈,然后立马出栈。随后 BCD 一次进栈, 那么出栈顺序一定为 DCB,所以上述方式合法。
当然也有不合法的,例如 ADBC就不合法。N个不同元素按顺序进栈,那么出栈顺序有 (1/n+1)Cn2n
种可能。
实现---动态顺序栈
顺序栈又可以分为静态(最大空间不可以改变),和动态,当然这里讨论的为 动态
实现的基本操作无非就是,创销增删改查

定义
我们既然使用顺序结构,那么就规定 连续存储结构的第一个位置为栈底,使用指针base指向 ;末尾作为栈顶,使用top指向;同时我们为了方便增大容量可以使用 stacksize
存储当前栈的容量.
如果栈使用数组存储,那么0号元素被base指向,top指向数组最后一个元素的下一个空位,方便下次存储数据。
#define InitSize 100 // 初始栈大小
#define Addsize 10 //每次增加栈创建的大小
typedef struct {
ElemType* base, * top;// 栈的基址(栈底指针)和 栈顶指针
int stacksize; //栈的大小
}SqStack;
Init初始化
我们规定 base == NULL时,栈不存在。规定空栈时候 top==base,每次插入一个元素,top向下移动一个位置。
bool Init_SqStack(SqStack& S)
{
S.base = (ElemType*)malloc(InitSize * sizeof(ElemType));
if (!S.base)return false; //大小开辟失败
S.top = S.base;
S.stacksize = InitSize;
return true;
}
GetTop 获取栈顶元素
获取栈顶元素,栈顶元素被 top-1 指向
bool GetTop(SqStack S, ElemType& e)
{
if (S.base == NULL)
return false;
e = *(S.top - 1);
return true;
}
Push元素入栈
推入元素的时候,为了算法的健全性,我们不仅要检查栈是否存在,如果存储空间不够(S.top-S.base>=stackSize)了还需要用relloc函数添加Addsize大小的空间
.当然使用realloc,记得注意事项哦!C语言 realloc注意事项
bool Push(SqStack& S, ElemType e)
{
if (S.base == NULL)
return false;
if (S.top - S.base >= S.stacksize)//空间不够了,增加空间
{
int* new_base = (ElemType*)realloc(S.top, (S.stacksize + AddSize) * sizeof(ElemType));
if (!new_base) return false;
S.base = new_base;
S.stacksize += AddSize;
}
*S.top++ = e;//先赋值后++
return true;
}
Pop 元素出栈
元素出栈,只需要改变top的指向,向后退一个即可,并且带回元素。当然也要考虑栈为空栈,就无需出栈了。
bool Pop(SqStack& S, ElemType& e)
{
if (S.base == NULL)
return false;
if (S.base == S.top) return false;
e = *--S.top;//先减减再取出元素
return true;
}
参考代码
# include<stdio.h>
# include<stdlib.h>
# define InitSize 100
# define AddSize 10
typedef struct {
int* base, * top;// 栈的基址(栈底指针)和 栈顶指针
int stacksize; //栈的大小
}SqStack;
bool Init_SqStack(SqStack& S);
bool GetTop(SqStack S, int& e);
bool Push(SqStack&S, int e);
bool Pop(SqStack&S, int& e);
void test()
{
SqStack S;
int e;
Init_SqStack(S);
printf("入栈数据 1--10\n");
for (int i = 1; i <= 10; i++)
Push(S, i);
printf("出栈5个数据\n\n");
for (int i = 1; i <= 5; i++)
{
Pop(S, e);
printf("此时 数据 :%3d 出栈\n", e);
}
printf("先进后出\n\n");
getchar();
}
int main()
{
test();
return 0;
}
bool Init_SqStack(SqStack& S)
{
S.base = (int*)malloc(InitSize * sizeof(int));
if (!S.base)return false;
S.top = S.base;
S.stacksize = InitSize;
return true;
}
bool GetTop(SqStack S, int& e)
{
if (S.base == NULL)
return false;
e = *(S.top - 1);
return true;
}
bool Push(SqStack& S, int e)
{
if (S.base == NULL)
return false;
if (S.top - S.base >= S.stacksize)//空间不够了,增加空间
{
int* new_base = (int*)realloc(S.top, (S.stacksize + AddSize) * sizeof(int));
if (!new_base) return false;
S.base = new_base;
S.stacksize += AddSize;
}
*S.top++ = e; //先赋值再++
return true;
}
bool Pop(SqStack&S, int& e)
{
if (S.base == NULL)
return false;
if (S.base == S.top) return false;
e = *--S.top; //先-- 再赋值
return true;
}