栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。
目录
void StackPush(Stack* ps, STDataType x)
STDataType StackTop(Stack* ps)
栈的结构体创建
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}Stack;
typedef int STDataType;
typedef struct Stack
{
STDataType* a; //a指向动态开辟好的那块空间
int top; //记录栈顶数据,它的位置是最后有数据的位置的下一个空间的位置,如上图所示
int capacity;//记录空间容量大小
}Stack;
函数接口的创建
//栈的初始化
void StackInit(Stack* ps);
//对栈空间的销毁
void StackDestroy(Stack* ps);
//压栈
void StackPush(Stack* ps, STDataType x);
//出栈
void StackPop(Stack* ps);
//栈空间里存放数据的个数
int StackSize(Stack* ps);
//栈顶数据
STDataType StackTop(Stack* ps);
//判断栈里面是否有数据
bool StackEmpty(Stack* ps);
void StackInit(Stack* ps)
void StackInit(Stack* ps)
{
assert(ps);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
刚开始使用栈空间时对栈的初始化
void StackInit(Stack* ps) //ps接收结构体的地址
{
assert(ps);//判断ps是否为有效地址
ps->a = NULL; //刚开始把a置为空,避免野指针乱用
ps->top = ps->capacity = 0;//栈顶数据和容量都初始化为0
}
void StackDestroy(Stack* ps)
void StackDestroy(Stack* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
对动态开辟好的栈空间进行销毁,不销毁的话会存在内存泄漏
oid StackDestroy(Stack* ps)
{
assert(ps);
free(ps->a);//ps->a的那块空间是一块连续的空间,只需要从起始位置释放就行了
ps->a = NULL;//置为空,防止a变成野指针
ps->top = ps->capacity = 0;
}
void StackPush(Stack* ps, STDataType x)
void StackPush(Stack* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
else
{
ps->a = tmp;
ps->capacity = newcapacity;
}
}
ps->a[ps->top] = x;
ps->top++;
}
从栈顶插入数据
void StackPush(Stack* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity) //判断容量是否满了,满了就需要增容
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2; //新空间的大小就等于:如 果原来空间大小为0,那么新空间大小就位4;否则新空间大小为原来空间大小的两倍
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);//用临时变量tmp来接收新空间,防止realloc开辟空间失败,把原来空间里面的数据都给销毁了;当ps->a==NULL时,realloc的功能就相当于malloc
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
else
{
ps->a = tmp;//如果开辟空间成功,就把开辟好空间地址给ps->a,(tmp是临时记录空间的指针)
ps->capacity = newcapacity;//记得此时空容量大小是新容量的大小,这一步不能忘
}
}
ps->a[ps->top] = x; //在栈顶插入数据
ps->top++; //栈顶的位置在往后+1
}
void StackPop(Stack* ps)
void StackPop(Stack* ps)
{
assert(ps);
assert(ps->top > 0);
ps->top--;
}
删除栈顶的数据
void StackPop(Stack* ps)
{
assert(ps);
assert(ps->top > 0);//判断栈空间里是否还有数据才能删除数据,否则会可能导致ps->top 指向的位置出现偏差,程序出现越界的问题。如果没有这句断言会出现这种情况:
红色的那块空间明显被非法使用了,因为这一块空间不属于自己申请的空间。按照正常来说,原来是想把数据100放入top==0的位置上,但是top的位置出现了偏差。ps->top--; //删除数据后ps->top减1,相当于数据个数减1
}
int StackSize(Stack* ps)
int StackSize(Stack* ps)
{
assert(ps);
return ps->top;
}
记录栈中的数据
int StackSize(Stack* ps)
{
assert(ps);
return ps->top; //栈顶的下标就代表数据个数如图:
数组是从下标为0的地方开始的,top指向最后一个数据的后面那块空间的下标,通过图来发现,top就相当于栈空间中的元素个数了
}
STDataType StackTop(Stack* ps)
STDataType StackTop(Stack* ps)
{
assert(ps);
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
返回栈顶的数据
STDataType StackTop(Stack* ps)
{
assert(ps);
assert(ps->top > 0);//当有栈中数据时就返回
return ps->a[ps->top - 1]; //top-1的位置是存放尾数据的地方
}
bool StackEmpty(Stack* ps)
bool StackEmpty(Stack* ps)
{
assert(ps);
return ps->top == 0;
}
判断栈空间里是否为空
bool StackEmpty(Stack* ps)
{
assert(ps);
return ps->top == 0;//当栈空间为空时,返回真,否则返回假
}
模拟栈的完整代码
Stack.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}Stack;
//栈的初始化
void StackInit(Stack* ps);
//对栈空间的销毁
void StackDestroy(Stack* ps);
//压栈
void StackPush(Stack* ps, STDataType x);
//出栈
void StackPop(Stack* ps);
//栈空间里存放数据的个数
int StackSize(Stack* ps);
//栈顶数据
STDataType StackTop(Stack* ps);
//判断栈里面是否有数据
bool StackEmpty(Stack* ps);
Stack.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"
void StackInit(Stack* ps)
{
assert(ps);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
void StackDestroy(Stack* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
void StackPush(Stack* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
else
{
ps->a = tmp;
ps->capacity = newcapacity;
}
}
ps->a[ps->top] = x;
ps->top++;
}
void StackPop(Stack* ps)
{
assert(ps);
assert(ps->top > 0);
ps->top--;
}
int StackSize(Stack* ps)
{
assert(ps);
return ps->top;
}
STDataType StackTop(Stack* ps)
{
assert(ps);
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
bool StackEmpty(Stack* ps)
{
assert(ps);
return ps->top == 0;
}
测试代码test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"
void StackTest1()
{
Stack st;
StackInit(&st);
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);
STDataType tmp = StackTop(&st);
printf("%d\n", tmp);
StackPop(&st);
tmp = StackTop(&st);
printf("%d\n", tmp);
int size = StackSize(&st);
printf("%d\n", size);
StackDestroy(&st);
}
int main()
{
StackTest1();
return 0;
}
测试结果: