1.栈 的 概 念 与 结 构
栈:
一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据的插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守LIFO(先进后出或后进先出的原则)。
压 栈:
栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出 栈:
栈的删除操作叫做出栈。出数据也在栈顶。
栈 底 层 结 构 选 型
栈的实现一般可以使用数组或者链表的实现,相对而言数组的结构实现更优一些。因为数组在尾插上插入数据的代价比较小。
2.栈的实现
依据前面数据结构的实现,在实现栈时,我们也需要三个文件。Stack.h(栈结构的定义以及函数的声明),Stack.c(函数功能的实现),test.c(函数功能的测试)。
2.1 Stack.h(栈结构的定义以及函数的声明)
#include <stdio.h> #include <stdlib.h> #include <assert.h> #include <stdbool.h> // 栈结构的定义以及函数功能的实现 先进后出 // //栈的结构的定义 用数组实现的时候时间复杂度较小,操作较为简单 。空间复杂度小 //缓存命中--数组(内存存储时连续) typedef int STDatatype; typedef struct Stack { STDatatype * arr; int top; int capacity; }ST; //函数的声明 //初始化 void STInit(ST* ps); //销毁 void STDestroy(ST* ps); //入栈 void STPush(ST* ps, STDatatype x); //判断栈是否为空 bool STEmptty(ST* ps); //出栈 void STPop(ST* ps); //获取栈顶元素 STDatatype STTop(ST* ps); //获取栈的数据元素的个数 int STSize(ST* ps);
2.2 Stack.c(函数功能的实现)
#include "Stack.h"
2.2.1 初始化
//初始化 void STInit(ST* ps) { assert(ps); ps->arr = NULL; ps->top = ps->capacity = 0; }
《实现思路》
先判断所传地址的有效性,再对指向数组的指针置为空,将top(也可以标记栈中数据的个数)和capacity(栈的空间大小)都置为0。
2.2.2 销毁
//销毁 void STDestroy(ST* ps) { assert(ps); if (ps->arr) free(ps->arr); ps->arr = NULL; ps->top = ps->capacity = 0; }
《实现思路》
先判断所传地址的有效性,如果指向数组的指针非空,则需要将动态申请的空间释放掉,并将其置为空。再top和capacity都置为0。
2.2.3 入栈
//入栈 void STPush(ST* ps, STDatatype x) { assert(ps); //先判断空间够不够,空间不够就需要动态增容 if (ps->top == ps->capacity) { int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity; STDatatype* temp = (STDatatype*)realloc(ps->arr, newcapacity * sizeof(STDatatype)); if (temp == NULL) { perror("realloc fail"); exit(1); } ps->arr = temp; ps->capacity = newcapacity; } ps->arr[ps->top++] = x; }
《实现思路》
先判断所传地址的有效性,再判断空间是否够(和前面的顺序表的空间大小判断一样,都是以二倍扩容)。最后通过指向数组的指针再下标为top的位置插入数据即可,除此之外top++。
2.2.4 判断栈是否为空
//判断栈是否为空 bool STEmptty(ST* ps) { assert(ps); return ps->top == 0; }
《实现思路》
先判断所传地址的有效性,对于判空只需要直接返回top为0即可,因为top不仅是标记当前栈顶的位置,也表示当前栈中的元素个数。
2.2.5 出栈
//出栈 void STPop(ST* ps) { assert(ps); assert(!STEmptty(ps)); ps->top--; }
《实现思路》
先判断所传地址的有效性,再进行判断栈是否为空,如果为空,就不能进行出栈操作。反之,栈不为空时,出栈只需要top--即可。
2.2.6 获取栈顶数据
//获取栈顶元素 STDatatype STTop(ST* ps) { assert(ps); assert(!STEmptty(ps)); return ps->arr[ps->top - 1]; }
《实现思路》
先判断所传地址的有效性,再进行判断栈是否为空,如果为空,就不能进行获取栈顶数据的操作。反之,栈不为空时,只需要通过指向数组的指针访问top-1位置的元素。因为top标示的是当前栈的数据个数,它是和栈顶数据的下标相差1的,并不相同。
2.2.7 获取栈中的数据个数
//获取栈的数据元素的个数 int STSize(ST* ps) { assert(ps); return ps->top; }
《实现思路》
先判断所传地址的有效性,再直接返回top的值即可。
2.3 test.c(函数功能的测试)
#include "Stack.h" //栈数据结构函数功能的测试部分 void STprint(ST* st) { while (!STEmptty(st)) { printf("%d ", STTop(st)); STPop(st); } printf("\n"); } void test() { ST st; STInit(&st); STPush(&st, 1); STPush(&st, 2); STPush(&st, 3); STPush(&st, 4); printf("size:%d\n", STSize(&st)); STprint(&st); printf("now size:%d\n", STSize(&st)); STDestroy(&st); } int main() { test(); return 0; }