这篇博客主要介绍栈的内容。
栈的介绍
定义: 栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈(入栈): 往栈中插入数据的操作叫做压栈,或者入栈。
出栈: 出栈就是删除栈中的数据。
入栈和出栈操作规则如下图所示
注意: 栈中最上方的数据就是栈顶,最下方的数据就是栈底。栈只能在顶部进行入栈出栈操作,因此栈中的数据是先进后出、后进先出的。
栈的结构
用代码实现的栈的结构如上图所示。对于栈,只在栈顶这一端对栈进行操作(插入或者删除数据),所以选用顺序表来存储数据比较适合,入栈出栈就是顺序表的尾插和尾删。
栈的结构体的定义
typedef int STDataType;
typedef struct Stack
{
STDataType* a; // 存储数据的数组首地址指针
int top; // 栈顶下标+1
int capacity; // 栈的最大容量
}Stack;
栈的实现
(1)栈的初始化
void StackInit(Stack* ps)
{
assert(ps);
// 初始时设置栈的容量为4
ps->a = (STDataType*)malloc(sizeof(STDataType)*4);
ps->top = 0;
ps->capacity = 4;
}
(2)入栈
void StackPush(Stack* ps, STDataType data)
{
assert(ps);
// 如果栈顶等于容量,说明栈已经满了,所以扩容,一次性扩大两倍
if (ps->top == ps->capacity)
{
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->capacity * 2);
if (tmp == NULL)
{
printf("realloc fail!\n");
exit(-1);
}
ps->a = tmp; // 如果当前内存不够扩,那就在另一块区域开辟,所以地址可能变了
ps->capacity *= 2;
}
ps->a[ps->top] = data;
ps->top++;
}
注意:
- 判断栈满的条件是
top==capacity
。容量最大为capacity,那么栈中数据最大下标是capacity-1,而top是栈顶下标+1,当top == capacity时说明栈已经存满了。 - 栈满将容量扩为当前容量的2倍。
(3)出栈
void StackPop(Stack* ps)
{
assert(ps);
if (ps->top == 0)
{
printf("栈已空!");
}
ps->top--;
}
(4)判断栈是否为空。为空返回1,非空返回0。
int StackEmpty(Stack* pst)
{
return pst->top == 0; // 为空返回1
}
(5)获取栈顶数据
STDataType StackTop(Stack* ps)
{
assert(ps);
assert(!StackEmpty(ps));
return ps->a[ps->top - 1];
}
(6)栈销毁
void StackDestroy(Stack* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = 0;
}
完整代码及测试程序
一共三个文件
Stack.h
头文件+结构体+声明文件Stack.c
接口函数实现文件Test_Stack.c
测试程序
#pragma once
#include<stdio.h>
#include<malloc.h>
#include<assert.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a; // 存储数据的数组首地址指针
int top; // 栈顶 - 栈里面最后一个元素下标+1
int capacity; // 栈的容量
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
#include "Stack.h"
void StackInit(Stack* ps)
{
assert(ps);
ps->a = (STDataType*)malloc(sizeof(STDataType)*4);
ps->top = 0;
ps->capacity = 4;
}
void StackPush(Stack* ps, STDataType data)
{
assert(ps);
// 如果栈顶等于容量,说明栈已经满了,所以扩容,一次性扩大两倍
if (ps->top == ps->capacity)
{
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->capacity * 2);
if (tmp == NULL)
{
printf("realloc fail!\n");
exit(-1);
}
ps->a = tmp; // 如果当前内存不够扩,那就在另一块区域开辟,所以地址可能变了
ps->capacity *= 2;
}
ps->a[ps->top] = data;
ps->top++;
}
void StackPop(Stack* ps)
{
assert(ps);
if (ps->top == 0)
{
printf("栈已空!");
}
ps->top--;
}
STDataType StackTop(Stack* ps)
{
assert(ps);
assert(!StackEmpty(ps));
return ps->a[ps->top - 1];
}
int StackEmpty(Stack* pst)
{
return pst->top == 0; // 为空返回1
}
void StackDestroy(Stack* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = 0;
}
#include"Stack.h"
void TestStack()
{
Stack s;
StackInit(&s);
printf("入栈1,2,3,4, 然后出栈\n");
StackPush(&s, 1);
StackPush(&s, 2);
StackPush(&s, 3);
StackPush(&s, 4);
// 注意:打印栈中数据的方式
while (!StackEmpty(&s))
{
printf("栈顶: %d\n", StackTop(&s));
StackPop(&s);
}
StackDestroy(&s);
}
int main()
{
TestStack();
return 0;
}