栈
1、栈是限定仅在表尾进行插入或者删除的操作
2、栈又被称为后进先出的线性表
3、顺序栈:栈的顺序存储结构,利用一组地址连续的存储单元依次存放,自栈底到栈顶的数据元素,同时依附指针top指示栈顶元素在顺序栈中的位置。
初始化栈
栈在使用过程中所需要的最大空间大小很难估计,所以在初始化时,不该定义一个最大容量。而是先分配一个合理容量,再依情况追加。
头文件和宏定义
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#define STACKSIZE 100
#define STACKINCRESE 10
#define SElemType int
#define Status int
存储结构
typedef struct {
SElemType *top;
SElemType *base;
int StackSize;
}SqStack;
初始化栈
void InitStack(SqStack &S,int num)
{
S.base = (SElemType*)malloc(STACKSIZE*sizeof(SElemType));
S.top = S.base;
S.StackSize = STACKSIZE;
if (num > S.StackSize)exit(-1);
for (int i = 0; i < num; i++) {
printf("请输入第%d个数据:", i + 1);
scanf("%d", &*S.top++);
}
}
销毁栈
销毁栈:使得栈不再存在,需要释放内存
释放内存之后让指针指向NULL,防止野指针
void DestroyStack(SqStack &S){
for (int i = 0; i < S.StackSize; i++)
{
free(S.base);
S.base++;
}
S.base = S.top = NULL;
S.StackSize = 0;
}
置为空栈
就是把栈置为初始的样子,base和top都在最下面
void ClearStack(SqStack &S){
S.top = S.base;
}
判断是否为空栈
判断空栈的条件就是base=top,即没有任何数据
bool StackEmpty(SqStack S) {
if (S.base == S.top)
return true;
return false;
}
求栈的长度
int StackLength(SqStack S) {
return S.top - S.base;
}
取栈顶元素
Status GetTop(SqStack &S) {
if (S.top == S.base)return -1;
return *(--S.top);
}
入栈
入栈就要考虑到栈是否以及满了,如果满就需要追加内存
void PushStack(SqStack &S, SElemType e) {
if (S.top - S.base >= S.StackSize) {
S.base = (SElemType*)realloc(S.base, (STACKINCRESE + STACKSIZE) * sizeof(SElemType));
//如果存储空间不够,追加存储
S.top = S.base + S.StackSize;//让新的top指针指向顶部
S.StackSize = STACKINCRESE + STACKSIZE;
}
*S.top++= e;
}
删除栈顶元素
对于这个功能,我在写代码的时候有一个这样的疑问:
参考代码是直接把栈顶元素取出返回了
top指针下移
我在想不是要删除栈顶元素吗,为什么没有free、置为null的操作。后来我把*S.top输出,结果为要删除的元素的值。
因为在栈中,它通过(*–S.top)的方式来取栈顶元素。在这里直接把S.top指向了要被删除的值,那么这个值,就永远都用指针访问不了,以栈的形式。意义上是实现了删除的操作
Status Pop(SqStack &S, SElemType &e) {
if (S.base == S.top)
return -1;
e = *(--S.top);
return 1;
//只是指针下移,但是S.top的值就是当前的e
//但是根据栈的特点没有办法再去访问它了
}
遍历栈
两种方法
1、从S.top开始–,这个是我自己写的
2、从S.base开始++
法一
之中使用一个新的指针指向S.top,来进行Top的变换
Status GetStack(SqStack &S) {
printf("此栈现在的元素为:\n");
if (S.top == S.base) return -1;
SElemType *p; p = S.top;
for (int i = 0; i < StackLength(S); i++) {
p--;
printf("%d\t", *(p));
}
return 1;
}
法二
之中传入一个函数visit函数用来输出访问了的元素
Status visit(SElemType e)
{
printf("%d\t", e);
return 1;
}
Status StackTraverse(SqStack S, Status(*visit)(SElemType)){
if (S.base == S.top)return -1;
int len = StackLength(S);
for (int i = 0; i <len; i++) {
visit(*(S.base++));
}
printf("\n");
return 1;
}
在法二中遇到的问题:
错误代码:
for (int i = 0; i <StackLength(S); i++) {
visit(*(S.base++));
}
最后输出的元素比原本初始化了的元素数量更少
错误原因:这样写的话,Base一直在变化,循环每走一次,Base就往上移动一次。而在函数StackLength中循环结束条件为S.top-S.base
,Base的值一直在增大,所以循环的次数也就一直在减少,导致最后打印的元素数量少了。
解决办法
1、
while (S.top>S.base)
visit(*(S.base++));
2、
用len记录长度,控制次数不变
int len = StackLength(S);
for (int i = 0; i <len; i++) {
visit(*(S.base++));
}