参考此文章数据结构——栈,此文章写的更详细,由于我们都是学自于比特课程,这里做个自我备份,方便后续查阅、修改和补充。
栈知识梳理和函数实现
- 前言
- 1.栈是什么?
- 2.栈的接口实现
- 2.1初始化栈
- 2.2入栈
- 2.3 出栈
- 2.4 获取栈顶元素
- 2.5 获取栈中有效元素个数
- 2.6 检测栈是否为空
- 2.7销毁栈
- 2.8 调试代码
前言
1.栈是什么?
栈(Stack):是只允许在一端进行插入或删除的线性表。首先栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作。
栈顶(Top):线性表允许进行插入删除的那一端。
栈底(Bottom):固定的,不允许进行插入和删除的另一端。
空栈:不含任何元素的空表。
栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构
2.栈的接口实现
栈与顺序表类似,可设计为定长的静态栈或支持动态增长的栈。然而,定长栈存在较大局限性,在实际中不太实用,因此我们主要实现支持动态增长的栈。
与之前的顺序表/链表接口实现相同,我们首先创建一个头文件“Stack.h”以及两个源文件“Stack.c”和“Test.c”,它们的具体作用如下:
- “Stack.h”:用于栈的定义、头文件的引用以及接口函数的声明。
- “Stack.c”:实现接口函数。
- “Test.c”:对各个函数进行测试。
我们先完整展示“Stack.h”的代码,同时别忘了在两个源文件中引用“Stack.h”。
#pragma once //防止头文件被二次引用#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>typedef int STDataType; //如果要修改存储的数据类型可直接在此修改typedef struct Stack
{STDataType* arr;int top;int capacity; //容量
}Stack;void StackInit(Stack* pst);//初始化栈void StackPush(Stack* pst, STDataType x);//入栈void StackPop(Stack* pst);//出栈STDataType StackTop(Stack* pst);//获取栈顶元素int StackSize(Stack* pst);//获取栈中有效元素个数bool StackEmpty(Stack* pst);//检测栈是否为空void StackDestory(Stack* pst);//销毁栈
2.1初始化栈
void StackInit(Stack* pst)
{assert(pst); //断言,防止传入空指针pst->arr = NULL; //初始化指针,置空pst->top = 0; //top指向栈顶数据的下一个位置pst->capacity = 0; //初始化容量
}
类似地,我们可将结构体中的 top 近似理解为数组的下标(虽然并非完全等同,但这样理解较为方便)。当我们在初始化栈时,将 top 初始化为 0,此时栈中无数据,top 指向栈顶数据的下一个位置。
当我们将 top 初始化为 -1 时,top 会指向栈顶数据的位置。
本文我们采用的是 top 初始值为 1 的情况。
2.2入栈
void StackPush(Stack* pst, STDataType x)
{if (pst->top == pst->capacity) //容量已满,需要扩容{int NewCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2; //如果容量为0则扩到4,否则扩为2倍STDataType* cmp = (STDataType*)realloc(pst->arr, NewCapacity * sizeof(STDataType));//创建一个临时指针变量来存储新空间地址,防止开辟失败if (cmp == NULL) //防止空间开辟失败出现空指针{perror("realloc fail");return;}pst->arr = cmp; //将临时指针变量中存放的新空间地址赋值给arrpst->capacity = NewCapacity; //空间容量更新}pst->arr[pst->top] = x; //将数据存放进栈顶元素的下一个位置pst->top++; //位置更新
}
2.3 出栈
void StackPop(Stack* pst)
{assert(pst); //断言,防止传入空指针assert(!StackEmpty(pst)); //断言,用检测空栈的函数返回值来判断,栈为空则不能出栈pst->top--; //位置更新
}
出栈只需要移动top的位置,把原来栈顶的元素“踢出”有效数据范围即可。StackEmpty函数将在后面讲到。
2.4 获取栈顶元素
STDataType StackTop(Stack* pst)
{assert(pst); //断言,防止传入空指针assert(!StackEmpty(pst)); //断言,用检测空栈的函数返回值来判断,栈为空则不能获取return pst->arr[pst->top - 1]; //top-1为栈顶元素位置,返回其值即可
}
2.5 获取栈中有效元素个数
int StackSize(Stack* pst)
{assert(pst); //断言,防止传入空指针return pst->top; //top即为有效元素个数
}
2.6 检测栈是否为空
bool StackEmpty(Stack* pst)
{assert(pst); //断言,防止传入空指针return pst->top == 0; //如果top为0表达式则为真,返回值为ture,反之为false
}
2.7销毁栈
bool StackEmpty(Stack* pst)
{assert(pst); //断言,防止传入空指针return pst->top == 0; //如果top为0表达式则为真,返回值为ture,反之为false
}
2.8 调试代码
所有接口都完成后,我们在Test.c中调试一下
#include "Stack.h"
void TestStack()
{ST st;StackInit(&st);StackPush(&st, 1);StackPush(&st, 2);StackPush(&st, 3);printf("%d ", StackTop(&st));StackPop(&st);printf("%d ", StackTop(&st));StackPop(&st);StackPush(&st, 4);StackPush(&st, 5);while (!StackEmpty(&st)){printf("%d ", StackTop(&st));StackPop(&st);}printf("\n");StackDestory(&st);
}
int main()
{TestStack();return 0;
}