github代码:
https://github.com/Kyrie-leon/Data_Structures/tree/main/stack_queue
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小,如下图所示。
而如果采用如下结构实现栈,尾插需要挪动数据,造成大量的计算开销。
静态存储的栈
使用一个静态一维数组a[N]实现,但这样做会造成太多的空间浪费或者空间不足
#define N 10
typedef int STDataType;
typedef struct Stack Stack;
struct Stack
{
STDataType a[N];
int _top; //栈顶
};
支持动态增长的栈
使用一个指针_a动态开辟内存实现栈的存储
typedef int STDataType;
typedef struct Stack Stack;
//支持动态增长的栈
struct Stack
{
STDataType * _a;
int _top; //栈顶
int _capacity; //容量
};
初始化:默认为栈开辟四个STDataType大小的空间
- capacity:栈的容量大小,默认4
- _top: 表示栈顶,我们约定_top=0表示栈为空,之后每入栈一个元素_top加1,即_top所指向数组的下表总是比实际栈顶元素下标大1
//栈的初始化
void StackInit(Stack * ps)
{
assert(ps);
ps->_a = (STDataType *)malloc(sizeof(Stack) * 4); //默认数组大小为4
ps->_top = 0; //栈为空,则栈顶为0
ps->_capacity = 4; //默认栈的容量为4
}
前面已经约定过_top所指向数组的下表总是比实际栈顶元素下标大1
入栈只需要将数据存放到_top下标的数组中,然后_top加1即可
//入栈
void StackPush(Stack * ps, STDataType data)
{
assert(ps);
//判断栈是否满了,满了则增容
if (ps->_top == ps->_capacity)
{
ps->_capacity *= 2; //每次扩容2倍
STDataType * tmp = (STDataType *)realloc(ps->_a, sizeof(Stack)*ps->_capacity);
//判断内存是否申请成功
if (NULL == tmp)
{
printf("扩容失败\n");
exit(-1);
}
ps->_a = tmp;
}
//入栈
ps->_a[ps->_top] = data;
ps->_top++;
}
_top所指向数组的下表总是比实际栈顶元素下标大1
因此出栈只需将_top减1即可
//出栈
void StackPop(Stack * ps)
{
assert(ps);
assert(ps->_top>0);
ps->_top--;
}
_top所指向数组的下表总是比实际栈顶元素下标大1
所以栈顶元素的下标是_top-1
//获取栈顶元素
STDataType StackTop(Stack *ps)
{
assert(ps);
assert(ps->_top>0);
return ps->_a[ps->_top-1];
}
因为数组元素下标从0开始,因此_top就表示栈中有效元素个数
//获取栈中有效元素个数
int StackSize(Stack * ps)
{
assert(ps);
return ps->_top;
}
通过_top的值就可以判断栈是否为空
若_top为0,表示为空,取反则返回非0
若_top为1,表示不为空,取反则返回0
//检测栈是否为空,如果为空返回非0,不为空返回0
int StackEmpty(Stack* ps)
{
assert(ps);
return !(ps->_top);
}
//销毁栈
void StackDestory(Stack * ps)
{
assert(ps);
free(ps->_a);
ps->_a = NULL;
ps->_capacity = ps->_top = 0;
}
#include "stack.h"
void TestStack()
{
Stack ps;
StackInit(&ps);
StackPush(&ps, 1);
StackPush(&ps, 2);
StackPush(&ps, 3);
StackPush(&ps, 4);
StackPush(&ps, 5);
while (!StackEmpty(&ps))
{
printf("%d, %d\n", StackTop(&ps),StackSize(&ps));
StackPop(&ps);
}
}
int main()
{
TestStack();
system("pause");
return 0;
}
#pragma once
#include
#include
#include
#include
#define N 10
typedef int STDataType;
typedef struct Stack Stack;
//struct Stack
//{
// STDataType a[N];
// int _top; //栈顶
//};
//支持动态增长的栈
struct Stack
{
STDataType * _a;
int _top; //栈顶
int _capacity; //容量
};
//初始化栈
void StackInit(Stack * ps);
//入栈
void StackPush(Stack * ps, STDataType data);
//出栈
void StackPop(Stack * ps);
//获取栈顶元素
STDataType StackTop(Stack *ps);
//获取栈顶中有效元素个数
int StackSize(Stack * ps);
//检测栈是否为空,如果为空返回非0,不为空返回0
int StackEmpty(Stack* ps);
//销毁栈
void StackDestory(Stack * ps);
#include "stack.h"
//栈的初始化
void StackInit(Stack * ps)
{
assert(ps);
ps->_a = (STDataType *)malloc(sizeof(Stack) * 4); //默认数组大小为4
ps->_top = 0; //栈为空,则栈顶为0
ps->_capacity = 4; //默认栈的容量为4
}
//入栈
void StackPush(Stack * ps, STDataType data)
{
assert(ps);
//判断栈是否满了,满了则增容
if (ps->_top == ps->_capacity)
{
ps->_capacity *= 2; //每次扩容2倍
STDataType * tmp = (STDataType *)realloc(ps->_a, sizeof(Stack)*ps->_capacity);
//判断内存是否申请成功
if (NULL == tmp)
{
printf("扩容失败\n");
exit(-1);
}
ps->_a = tmp;
}
//入栈
ps->_a[ps->_top] = data;
ps->_top++;
}
//出栈
void StackPop(Stack * ps)
{
assert(ps);
assert(ps->_top>0);
ps->_top--;
}
//获取栈顶元素
STDataType StackTop(Stack *ps)
{
assert(ps);
assert(ps->_top>0);
return ps->_a[ps->_top-1];
}
//获取栈中有效元素个数
int StackSize(Stack * ps)
{
assert(ps);
return ps->_top;
}
//检测栈是否为空,如果为空返回非0,不为空返回0
int StackEmpty(Stack* ps)
{
assert(ps);
return !(ps->_top);
}
//销毁栈
void StackDestory(Stack * ps)
{
assert(ps);
free(ps->_a);
ps->_a = NULL;
ps->_capacity = ps->_top = 0;
}
#include "stack.h"
void TestStack()
{
Stack ps;
StackInit(&ps);
StackPush(&ps, 1);
StackPush(&ps, 2);
StackPush(&ps, 3);
StackPush(&ps, 4);
StackPush(&ps, 5);
while (!StackEmpty(&ps))
{
printf("%d, %d\n", StackTop(&ps),StackSize(&ps));
StackPop(&ps);
}
}
int main()
{
TestStack();
system("pause");
return 0;
}