目录
[2.1 初始化栈](#2.1 初始化栈)
[2.2 入栈](#2.2 入栈)
[2.3 检测栈是否为空](#2.3 检测栈是否为空)
[2.3 出栈](#2.3 出栈)
[2.5 获取栈顶元素](#2.5 获取栈顶元素)
[2.6 获取栈中有效元素个数](#2.6 获取栈中有效元素个数)
[2.7 栈的销毁](#2.7 栈的销毁)
前言
前面,我们学习过了线性表中的顺序表和链表,今天我们来了解一下线性表的另外一种栈。
**栈是后进先出(LIFO)的数据结构。**这意味着最后一个进入栈的元素总是第一个出来的。栈的操作限制在栈顶进行,即只能从栈顶插入(入栈)和删除(出栈),这种特性使得栈符合后进先出的原则。
一、栈
栈:一种特殊的 线性表 ,其只允许在 固定的一端 进行插入和删除元素操作。**进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。**栈中的数据元素遵守后进先出 LIFO (Last In First Out)的原则。
压栈: 栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈: 栈的删除操作叫做出栈。出数据也在栈顶。
二、栈的实现
栈的实现一般可以使用 数组或者链表 实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。
我们通过数组来实现栈,就可以用定长的静态栈的结构,实际中一般不实用,所以我们主要实现下面的支持动态增长的栈
主要接口:
cpp
typedef int STDataType;
//栈
typedef struct Stack {
STDataType* a;
int top; //栈顶元素
int capacity;//容量
}ST;
//栈的初始化
void StackInit(ST* ps);
//入栈
void StackPush(ST* ps, STDataType x);
//出栈
void StackPop(ST* ps);
//获取栈顶元素
STDataType StackTop(ST* ps);
// 获取栈中有效元素个数
int StackSize(ST* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
bool StackEmpty(ST* ps);
//栈的销毁
void StackDestroy(ST* ps);
2.1 初始化栈
cpp
//栈的初始化
void StackInit(ST* ps) {
assert(ps);
ps->a = NULL;
ps->top = 0;//0为栈顶的下一个元素 -1为栈顶元素
ps->capacity = 0;
}
我们初始化栈内元素为空,栈顶元素为和栈的容量为0。
2.2 入栈
cpp
void StackPush(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->a, newcapacity * sizeof(STDataType));
if (temp == NULL)
{
perror("realloc fail");
}
ps->a = temp;
ps->capacity = newcapacity;
}
//入栈
ps->a[ps->top] = x;
ps->top++;
}
入栈操作相当于顺序表中的尾插操作,我们要先判断栈的大小是否足够,不够我们要先进行扩容操作,再先栈顶插入元素,插入的元素变成新的栈顶(即栈顶元素加1)。
2.3 检测栈是否为空
cpp
bool StackEmpty(ST* ps) {
assert(ps);
return ps->top == 0;
}
如果链表为空,则栈顶为零对于零为真,返回ture,反之不为空返回false。
2.3 出栈
cpp
//出栈
void StackPop(ST* ps) {
assert(ps);
assert(!StackEmpty(ps));//判空
ps->top--;
}
如果出栈,只需要把栈顶减一,不需要进行删除操作。
2.5 获取栈顶元素
cpp
//获取栈顶元素
STDataType StackTop(ST* ps) {
assert(ps);
assert(!StackEmpty(ps));//判空
return ps->a[ps->top-1];
}
top初始化为0,即栈顶元素的下一个,所以减一即为栈顶元素。
2.6 获取栈中有效元素个数
cpp
// 获取栈中有效元素个数
int StackSize(ST* ps) {
assert(ps);
return ps->top;
}
有效元素的个数就是栈顶,因为栈顶从零开始的。
2.7 栈的销毁
cpp
void StackDestroy(ST* ps) {
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
直接释放开辟的空间,同时栈的栈顶和容量都变为零。
三、完整代码
Stack.h
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>
typedef int STDataType;
//栈
typedef struct Stack {
STDataType* a;
int top; //栈顶元素
int capacity;//容量
}ST;
//栈的初始化
void StackInit(ST* ps);
//入栈
void StackPush(ST* ps, STDataType x);
//出栈
void StackPop(ST* ps);
//获取栈顶元素
STDataType StackTop(ST* ps);
// 获取栈中有效元素个数
int StackSize(ST* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
bool StackEmpty(ST* ps);
//栈的销毁
void StackDestroy(ST* ps);
Stack.c
cpp
#include"Stack.h"
//栈的初始化
void StackInit(ST* ps) {
assert(ps);
ps->a = NULL;
ps->top = 0;//0为栈顶的下一个元素 -1为栈顶元素
ps->capacity = 0;
}
//入栈
void StackPush(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->a, newcapacity * sizeof(STDataType));
if (temp == NULL)
{
perror("realloc fail");
}
ps->a = temp;
ps->capacity = newcapacity;
}
//入栈
ps->a[ps->top] = x;
ps->top++;
}
//出栈
void StackPop(ST* ps) {
assert(ps);
assert(!StackEmpty(ps));
ps->top--;
}
//获取栈顶元素
STDataType StackTop(ST* ps) {
assert(ps);
assert(!StackEmpty(ps));
return ps->a[ps->top-1];
}
// 获取栈中有效元素个数
int StackSize(ST* ps) {
assert(ps);
return ps->top;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
bool StackEmpty(ST* ps) {
assert(ps);
return ps->top == 0;
}
//栈的销毁
void StackDestroy(ST* ps) {
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
test.c
cpp
#include"Stack.h"
int main() {
ST s;
StackInit(&s);
StackPush(&s, 1);
StackPush(&s, 2);
StackPush(&s, 3);
StackPop(&s);
int top = StackTop(&s);
printf("%d ", top);
StackPush(&s, 4);
StackPush(&s, 5);
while(!StackEmpty(&s))
{
int top = StackTop(&s);
printf("%d ", top);
StackPop(&s);
}
StackDestroy(&s);
}
总结
上述文章,我们讲了线性表中的栈的概念和具体实现,希望对你有所帮助。