1 概念与结构
栈:⼀种特殊的线性表,其只允许在固定的⼀端进⾏插⼊和删除元素操作。进⾏数据插⼊和删除操作 的⼀端称为栈顶,另⼀端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插⼊操作叫做进栈/压栈/⼊栈,⼊数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
栈的实现⼀般可以使⽤数组或者链表实现,相对⽽⾔数组的结构实现更优⼀些。因为在前链表中尾插需要遍历单链表,时间复杂度比数组尾插的时间复杂度高,数组在尾上插入数据的代价⽐较⼩,并且栈不存在从栈底直接取出,必须满足从栈顶取出,就不存在非空的头插,所以不论是出栈,入栈数组的时间复杂度都为o(1)。
2 栈的实现
和前面的数据结构实现一样,创建三个文件stack.h,stack.c,test.c,分别为头文件,函数实现文件,以及测试文件(检验实现的函数是否正确)。
stack.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int SDataType;typedef struct Stack
{SDataType* arr;int top;int capacity;
}ST;void StackInit(ST*ps);
void StackDestory(ST* ps);void StackPush(ST* ps, SDataType x);
void StackPop(ST* ps);SDataType StackTop(ST* ps);
int STSize(ST* ps);
这里很之前的一样,栈里存的元素。可以是各种数据类型,为了方便后续改成其他类型,这里重定义数据类型为SDataType,这里以int为例,Stack结构体里,包含数组,栈顶位置top,以及空间大小capacity。
初始化StackInit
void StackInit(ST*ps)
{assert(ps);ps->arr = NULL;ps->top = ps->capacity = 0;
}
断言传的指针非空,数组置为空,栈顶为置和空间大小都为0.
入栈StackPush
void StackPush(ST* ps, SDataType x)
{assert(ps);if (ps->top == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SDataType* tmp = (SDataType*)realloc(ps->arr,newcapacity * sizeof(SDataType));if (tmp == NULL){perror("realloc fail!");exit(1);}ps->arr = tmp;ps->capacity = newcapacity;}ps->arr[ps->top] = x;ps->top++;
}
断言传的指针非空,首先要判断空间是否满了,或者空间大小为零,这里就需要申请空间,申请的大小每次为上一次的两倍,如果开始大小为零,则先申请4个大小的空间,然后对top栈顶位置的元素赋值x,最后top位置向后移动++。
判断栈为空StackEmpty
bool StackEmpty(ST*ps)
{assert(ps);return ps->top == 0;
}
这里利用bool类型返回,先断言传的指针非空,这里通过判断top位置是否为0,来判断栈是否为空。
出栈StackPop
void StackPop(ST* ps)
{assert(!StackEmpty(ps));ps->top--;
}
先判断栈是否为空,为空则不能出栈,这里直接将top位置向前移动一位,相当于合法访问的位置比原来的栈少了一个,即将栈顶元素拿出来了。
读取栈顶元素StackTop
SDataType StackTop(ST* ps)
{assert(!StackEmpty(ps));return ps->arr[ps->top-1];
}
先判断栈是否为空,为空则没有栈顶元素,这里直接通过数组下标访问,找到栈顶元素。
元素个数STSize
int STSize(ST* ps)
{assert(ps);return ps->top;
}
断言传的指针非空,直接返回Top位置,即为数组元素个数。
销毁栈StackDestory
void StackDestory(ST* ps)
{if (ps->arr != NULL){free(ps->arr);}ps->arr = NULL;ps->top = ps->capacity = 0;
}
先销毁数组中元素,不为空,就直接释放掉,置为空,栈顶位置和空间大小都置为0。
3.整体代码
Stack.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int SDataType;typedef struct Stack
{SDataType* arr;int top;int capacity;
}ST;void StackInit(ST*ps);
void StackDestory(ST* ps);void StackPush(ST* ps, SDataType x);
void StackPop(ST* ps);SDataType StackTop(ST* ps);
int STSize(ST* ps);
Stack.c
#include"Stack.h"
void StackInit(ST*ps)
{assert(ps);ps->arr = NULL;ps->top = ps->capacity = 0;
}void StackDestory(ST* ps)
{if (ps->arr != NULL){free(ps->arr);}ps->arr = NULL;ps->top = ps->capacity = 0;
}void StackPush(ST* ps, SDataType x)
{assert(ps);if (ps->top == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SDataType* tmp = (SDataType*)realloc(ps->arr,newcapacity * sizeof(SDataType));if (tmp == NULL){perror("realloc fail!");exit(1);}ps->arr = tmp;ps->capacity = newcapacity;}ps->arr[ps->top] = x;ps->top++;
}bool StackEmpty(ST*ps)
{assert(ps);return ps->top == 0;
}
void StackPop(ST* ps)
{assert(!StackEmpty(ps));ps->top--;
}SDataType StackTop(ST* ps)
{assert(!StackEmpty(ps));return ps->arr[ps->top-1];
}int STSize(ST* ps)
{assert(ps);return ps->top;
}