前言
栈是一种经典的先进后出的数据结构,今天我们来用C语言手撕一个栈。首先我们清楚栈是一种线性结构,而作为线性结构,它可以选择用顺序储存结构(顺序表),当然也可以用非顺序储存结构(链表)。今天我们就来逐步的用顺序表来实现一个栈。
首先是基本的预处理头文件:
#include <stdio.h>
#include <stdlib.h>
#define eletype int //宏定义一个数据类型,方便后期存不同的数据(int或者float或者double)
然后我们要清楚栈中需要存哪些元素,还有那些数据是我们将来要用到的,先想好这些我们就可以来创建一个结构类型的变量里面包含我们需要的数据项。
结构体的定义:
typedef struct Stack {
eletype *elements; //因为我们用顺序表实现栈,所以定义一个eletype型的数组elements来存储元素
int size; //在后面实现栈的相关操作时,我们需要用到栈的长度size
int capacity; //为了实现空间的高效利用,我们动态申请内存,capacity为申请数组内存的最大容量
} Stack;
1.栈的创建
此时我们回想下,刚才在栈的结构体中定义了哪些变量:数组elements、栈的长度size、栈的最大容量capacity。
这些变量在我们创建栈的时候都要进行初始化:
viod StackCreat (Stack *stk) {
stk->elements=(eletype*)malloc( sizeof(eletype)*8 ); //调用malloc函数实现动态分配内存
stk->size=0; //将栈的长度初始化为0
stk->capacity=8; //将栈的最大容量初始化为8
}
2.栈的销毁
栈的销毁则与栈的创建相反,需要将栈结构体中的元素都清空:
void StackDestroy (Stack *stk) {
free(stk->elements); //将数组的空间释放掉,并且要将其指向空NULL,避免造成错误
stk->elements==NULL;
stk->size=0; //将size、capacity赋值为0
stk->capacity=0;
}
3.栈的扩容
因为我们在创建栈时,只为数组elements分配了最大容量capacity=8的内存,所以当需要存储的数据量大于最大容量8时,我们就要为数组elements再分配一定的内存:
void StackResize (Stack *stk) {
eletype *new_elements=(eleltype*)realloc(stk->elements,sizeof(eletype)*(stk->capacity*2));
//定义一个与elements类型相同的数组new_elements
//调用realloc函数重新分配elements
elements=new_elements; //将新分配的内存地址更新给元素组
stk->capacity *=2; //同时将栈的最大容量乘2
}
4.入栈
入栈是将新的元素插入到现有的栈中,故而子函数的参数列表中应该有已有的栈中数组elements和需要压入的新元素element。此时我们思考一下,入栈时需要考虑哪些情况:可能栈中没有元素,可能栈中数组elements空间不足(需要重新分配空间,且要保证空间分配成功):
void StackPush (Stack *stk,eletype element) {
if(stk->size==stk->capacity){ //判断栈是否已满,若是,则调用函数StackResize()
StackResize (stk);
}
stk->elements[stk->size++]=element; //然后将element存入数组elements
}
5.出栈
我们知道栈的原则是先进后出,故而我们只需要将最后一个元素(索引为size-1)删除,同时将这元素带出即可。在这里我们同样要考虑栈为空的情况:
eleytpe StackPop (Stack *stk) {
if(stk->size==0){
printf("Stack is empty!\n"); //如果栈为空,将打印相关警告
exit(1);
}
return stk->elements[--stk->size]; //注意理解这里的--size,是先执行--操作,在结果带入命令
}
6.获取栈顶元素
获取栈顶元素的思路和出栈基本一致,但是只需要将元素带出,不需要做删除操作:
eletype StackTop (Stack *stk) {
if(stk->size==0){
printf("Stack is empty!\n");
exit(1);
}
return stk->elements[stk->size-1];
}
7.获取栈的长度
int StackGetsize (Stack *stk) {
reutrn stk->size;
}
8.完整代码
#include <stdio.h>
#include <stdlib.h>
#define eletype int //宏定义一个数据类型,方便后期存不同的数据(int或者float或者double)
typedef struct Stack {
eletype *elements;//因为我们用顺序表实现栈,所以定义一个eletype型的数组elements来存储元素
int size; //在后面实现栈的相关操作时,我们需要用到栈的长度size
int capacity; //为了实现空间的高效利用,我们动态申请内存,capacity为申请数组内存的最大容量
} Stack;
void StackCreat (Stack *stk) {
stk->elements=(eletype*)malloc( sizeof(eletype)*8 ); //调用malloc函数实现动态分配内存
stk->size=0; //将栈的长度初始化为0
stk->capacity=8; //将栈的最大容量初始化为8
}
void StackDestroy (Stack *stk) {
free(stk->elements); //将数组的空间释放掉,并且要将其指向空NULL,避免造成错误
stk->elements==NULL;
stk->size=0; //将size、capacity赋值为0
stk->capacity=0;
}
void StackResize (Stack *stk) {
eletype *new_elements=(eletype*)realloc(stk->elements,sizeof(eletype)*(stk->capacity*2));
//定义一个与elements类型相同的数组new_elements
//调用realloc函数重新分配elements
stk->elements=new_elements; //将新分配的内存地址更新给元素组
stk->capacity *=2; //同时将栈的最大容量乘2
}
void StackPush (Stack *stk,eletype element) {
if(stk->size==stk->capacity){ //判断栈是否已满,若是,则调用函数StackResize()
StackResize (stk);
}
stk->elements[stk->size++]=element; //然后将element存入数组elements
}
eletype StackPop (Stack *stk) {
if(stk->size==0){
printf("Stack is empty!\n"); //如果栈为空,将打印相关警告
exit(1);
}
return stk->elements[--stk->size];//注意理解这里的--size,是先执行--操作,在结果带入命令
}
eletype StackTop (Stack *stk) {
if(stk->size==0){
printf("Stack is empty!\n");
exit(1);
}
return stk->elements[stk->size-1];
}
int StackGetsize (Stack *stk) {
return stk->size;
}
int main(){
Stack stk;
StackCreat(&stk);
StackPush(&stk,10);
StackPush(&stk,20);
StackPush(&stk,30);
printf("栈顶元素为:%d\n",StackTop(&stk));
printf("出栈:%d\n",StackPop(&stk));
printf("栈的大小为:%d\n",StackGetsize(&stk));
StackDestroy(&stk);
return 0;
}
后记
如有分布解析是的代码错误,敬请指出!(分布解析的代码没有经过调试)