typedef int STDataType;
typedef struct Stack
{
STDataType* a; //指针
int top; //栈顶
int capacity; //容量
}ST;
目录
[1.void STInit(ST* pst);](#1.void STInit(ST* pst);)
[2.void STDestroy(ST* pst);](#2.void STDestroy(ST* pst);)
[3.void STPush(ST* pst, STDataType x); //没有头插头删、只有push栈顶压栈](#3.void STPush(ST* pst, STDataType x); //没有头插头删、只有push栈顶压栈)
[4.void STPop(ST* pst); //出栈](#4.void STPop(ST* pst); //出栈)
[5.STDataType STTop(ST* pst); //栈顶元素](#5.STDataType STTop(ST* pst); //栈顶元素)
[6.bool STEmpty(ST* pst); //判空](#6.bool STEmpty(ST* pst); //判空)
[7.int STSize(ST* pst); //大小](#7.int STSize(ST* pst); //大小)
一、函数声明
1.void STInit(ST* pst);
2.void STDestroy(ST* pst);
3.void STPush(ST* pst, STDataType x); //没有头插头删、只有push栈顶压栈
4.void STPop(ST* pst); //出栈
5.STDataType STTop(ST* pst); //栈顶元素
6.bool STEmpty(ST* pst); //判空
7.int STSize(ST* pst); //大小
二、函数功能
void STInit(ST* pst)
{
assert(pst); //不能为空。 不可以malloc(1.二级指针 2.返回值)一个结构体空间给pst,以及指针不能改变实参!
pst->a = NULL;
//pst->top = -1; // top 指向栈顶数据 先++ 再插入
pst->top = 0; // top 指向栈顶数据的下一个位置 //先插入 再++ //top可以理解为元素个数!!!
pst->capacity = 0; //一般都初始化为0
}
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL; //需要置空
pst->top = pst->capacity = 0; //置零
}
void STPush(ST* pst, STDataType x)
{
if (pst->top == pst->capacity) //满了,都直接用realloc(不用malloc)
{
int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2; //表达式为真,4倍,否则开辟二倍空间 //只有有空间,pst->capacity * 2 才不为零
STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
pst->a = tmp;
pst->capacity = newCapacity;
}
//先防止,后++
pst->a[pst->top] = x; //top本身就是指向下一个
pst->top++;
}
void STPop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
pst->top--; //没必要抹除数据,直接--就可以。当自此使用下一块空间时,借助下标top,可以修改对应空间
}
STDataType STTop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst)); //断言会直接结束,不为空再往下
return pst->a[pst->top - 1]; //下标是元素个数 - 1 //越界编译器不一定报错
}
bool STEmpty(ST* pst)
{
assert(pst);
/*if (pst->top == 0)
{
return true; // == 0 返回真
}
else
{
return false;
}*/
return pst->top == 0; // 直接这么写,判断是不是等于0 //比较运算符 == 的结果就是 真或假
}
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
三、栈使用
//规律:1. 一般出一个,访问一个! 2. 一般访问完栈之后,栈也会置空
while (!STEmpty(&st)) //访问元素 STEmpty(&st)(判断top是否为0)
{
printf("%d ", STTop(&st)); //一般只访问栈顶
STPop(&st); //弹出栈顶元素 (top--)
}
STDestroy(&st);
四、讲解
1.使用的时候,对于
STPop(&st); //删除
STEmpty(&st); //判空
这两个函数而言,都是通过top(栈成员数量)实现的。
2.压栈时,都要判断空间是否足够
3.出栈时,都要判断指针a指向的空间是否还有有效数据
4.top的大小就是元素个数。top初始化为0时,top指向栈顶下一个空间。应该先push再++。
5.ST->top - 1 表示下标
6.出栈直接top--,无需其他操作。
当全部出栈时,top == 0,会被判空。
7.进行压栈时,要先判断有没有足够空间。
只不过不同于链表,不需要额外的buy------list------node函数,在push函数中,可以直接进行空间开辟。
8.开辟空间时,而可以都使用realloc
int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2; //表达式为真,4倍,否则开辟二倍空间 //只有有空间,pst->capacity * 2 才不为零
== 判断操作符,可以返回真或假。
STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));
//STDataType 为数据类型
capacity若为0,则开辟 4 * sizeof(int)的空间,否则开辟2 * 原空间。
// if (tmp == NULL) 记得要判断是否开辟失败!
perror("realloc fail");
return; //开辟失败直接返回,函数结束。
开辟结束
pst->a = tmp; //指向新空间。
pst->capacity = newCapacity; //对应新容量。
if (pst->top == pst->capacity) //满了,都直接用realloc(不用malloc)
{
int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2; //表达式为真,4倍,否则开辟二倍空间 //只有有空间,pst->capacity * 2 才不为零
STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
pst->a = tmp;
pst->capacity = newCapacity;
}
当容量不够,此段代码扩容。
pst->a[pst->top] = x; //top本身就是指向下一个
pst->top++;
压栈之后,先赋值pst->a[pst->top] = x,再pst->top++;
需要注意的是top、a都是栈的成员变量,都需要->解引用!
9.STDataType STTop(ST* pst) //返回不是int,而是栈顶数据类型!
当size函数返回时,才返回int类型(个数)。
10.销毁只需要free(pst->a);并且置空就可以!
同时容量capacity置零。
五、注意点:
所有的结构体成员,都与要用指针 -> 解引用使用!(成员变量属于结构体)