栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一段称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优更优一些。因为数组在尾上插入数据的代价比较小。
使用结构体来定义栈,这个结构中包含了用来储存数据的数组、栈的顶部、栈的容量。
定义静态的栈
//定义静态的栈 #define N 100 typedef int STDataType; struct Stack { STDataType a[N]; int top; };
静态的栈限制这个栈只能储存N个数据,一旦储存的数据超过N个,就不行了。因此一般定义动态的栈
定义动态的栈
//定义动态的栈 typedef int STDataType; typedef struct Stack { STDataType* a; int top; //栈顶的位置(数组尾部的下标) int capacity; //栈的容量 }ST;
栈顶部的位置即是数组尾部的下标,栈的顶部也表示此时栈中储存元素的个数。
//初始化栈 void StackInit(ST* ps) { assert(ps); ps->a = NULL; ps->top = ps->capacity = 0; }
- 函数中的参数用结构体指针类型接收
- 栈中还没有储存数据时,将指向储存数据的数组置为空,栈顶的位置与栈的容量此时也为0。
//栈的销毁 void StackDestroy(ST* ps) { assert(ps); free(ps->a); ps->a = NULL; ps->capacity = ps->top = 0; }
- 直接将储存数据的数组释放,并将其置为空。
- 将栈的顶部与容量赋值为零。
//判空函数 bool StackEmpty(ST* ps) { assert(ps); return ps->top == 0; }
- 当栈为空时返回的为真,栈不为空时返回的为假。
//入栈 void StackPush(ST* ps, STDataType x) { assert(ps); if (ps->top == ps->capacity) { int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2; STDataType* tmp = (STDataType*)realloc(ps->a, newCapacity*sizeof(STDataType)); if (tmp==NULL) { perror("realloc fail"); exit(-1); } ps->a = tmp; 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]; }
- 栈顶元素即结构体中的数组成员的尾部元素,所以返回栈顶元素,返回就是数组尾部的元素。
在主函数中调用
void TestStack() { ST st; StackInit(&st); StackPush(&st, 1); StackPush(&st, 2); StackPush(&st, 3); StackPush(&st, 4); StackPush(&st, 5); //因为栈后进先出的特点,要遍历栈,栈就被清空了 while (!StackEmpty(&st)) { printf("%d ", StackTop(&st)); StackPop(&st); } printf("\n"); } int main() { TestStack(); return 0; }
- 将1 2 3 4 5通过入栈依次插入,然后通过返回栈顶元素与出栈将栈中的所有元素都访问了一遍,通过打印结果可以看到栈的特点是先进后出的。
栈的大小即栈当前储存元素的个数
//判断栈的大小 int StackSize(ST* ps) { assert(ps); return ps->top; //数组以0位置开始储存数据, 最后一个数据的下一个位置,正好是数据的个数 }
- 数组以0位置开始储存数据, 最后一个数据的下一个位置,正好是数据的个数、
Stack.h文件:写函数的声明,函数的头文件,其他 .c文件只要包含Stack.h文件——>#include “Stack.h”,就相当于写了函数的声明与头文件。如下:
#pragma once
#include
#include
#include
#include
定义静态的栈
//#define N 100
//typedef int STDataType;
//struct Stack
//{
// STDataType a[N];
// int top;
//};
//定义动态的栈
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top; //栈顶的位置(数组尾部的下标)
int capacity; //栈的容量
}ST;
//初始化栈
void StackInit(ST* ps);
//栈的销毁
void StackDestroy(ST* ps);
//入栈
void StackPush(ST* ps, STDataType x);
//出栈
void StackPop(ST* ps);
//返回栈顶元素
STDataType StackTop(ST* ps);
//判空函数
bool StackEmpty(ST* ps);
//判断栈的大小
int StackSize(ST* ps);
Stack.c文件:用来实现栈的各种功能接口函数。如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include "Stack.h"
//初始化栈
void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
//栈的销毁
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
//入栈
void StackPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, newCapacity*sizeof(STDataType));
if (tmp==NULL)
{
perror("realloc fail");
exit(-1);
}
ps->a = tmp;
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];
}
//判空函数
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
//判断栈的大小
int StackSize(ST* ps)
{
assert(ps);
return ps->top; //数组以0位置开始储存数据, 最后一个数据的下一个位置,正好是数据的个数
}
Test.c文件:主函数写在这,在主函数中可以调用 Stack.c文件中实现的各种接口。如下:
#define _CRT_SECURE_NO_WARNINGS 1 #include "Stack.h" void TestStack() { ST st; StackInit(&st); StackPush(&st, 1); StackPush(&st, 2); StackPush(&st, 3); StackPush(&st, 4); StackPush(&st, 5); //因为栈后进先出的特点,要遍历栈,栈就被清空了 while (!StackEmpty(&st)) { printf("%d ", StackTop(&st)); StackPop(&st); } printf("\n"); } int main() { TestStack(); return 0; }