在今天的学习中,将会介绍栈和队列的概念,以及其功能的实现,还有其应用场景
前言
栈是一种特殊的线性表,只允许在固定的一端进行插入和删除操作,这个端叫做栈顶,另一端叫做栈底,栈中元素遵循后进先出原则。
压栈:栈的插入操作叫压栈/入栈1/进栈
出栈:栈的删除操作叫做出栈
这个栈我们怎么理解它呢,他就像一个弹夹一样,每一颗子弹就相当于一个元素,子弹怎么进呢?肯定是先进最里面,再一颗一颗往上垒对吧,那子弹是怎么出弹夹的呢?就是从最顶上的开始,一颗一颗出去对吧,最顶上就相当于栈顶,放子弹是压栈,射击就是出栈了。(砰砰!)
我们也可以形象的把图画出来一下,方便我们后来实现。
大概就是这样,下面我们来看看怎么实现,如何实现。
栈的实现
栈也是线性表的一种,那么之前我们学过两种线性表,一种是链表,一种是顺序表。谁更适合栈的实现呢?其实两种都可以,但是如果使用顺序表的话,尾插的时候我们可以直接插入,访问有效节点个数的下标,但如果是单链表,我们压栈的时候就需要遍历一遍才能往里面压栈了。综上,我们直接用线性表实现栈。
1.初始化栈
2.检查容量
3.入栈
4.出栈
5.检查栈是否为空
6.销毁栈
栈的功能不多,也很好理解,就是一种特殊的线性表。
1.初始化栈
初始化之前我们先看看一些声明
typedef int STDataType;
typedef struct Stack
{
STDataType* _a;
int size;//有效数据个数
int _capacity; // 容量
}Stack;
下面是初始化:
// 初始化栈
void StackInit(Stack* ps)
{
ps->_a = (STDataType *)calloc(DEFSTACKSIZE,sizeof(STDataType));
ps->_capacity = DEFSTACKSIZE;
ps->size = 0;
}
没啥说的,很简单;
2.检查容量
栈也是会到顶的,空间不是无限的,都是我们给的,所以要注意每次插入之前考虑栈的容量问题
void CheckCapacity(Stack* ps)
{
if(ps->size >= ps->_capacity)
{
ps->_capacity *= 2;
ps->_a = (STDataType *)realloc(ps->_a,ps->_capacity*sizeof(STDataType));
}
}
当然,如果这么扩容就会出现空间浪费的问题,这不能避免。
3.入栈
入栈只能从栈顶入,这是栈的规则,我们结构体中的size现在就相当于栈顶的上面,这个位置是没有元素的,所以直接在这个位置插入就好:
void StackPush(Stack* ps, STDataType data)
{
CheckCapacity(ps);
ps->_a[ps->size] = data;
ps->size++;
}
4.出栈
// 出栈
void StackPop(Stack* ps)
{
if(ps->size == 0)
return ;
ps->size--;
}
出栈就很简单了,直接让size-- ,就代表栈顶元素没了,栈顶向前移一位。
5.检查栈是否为空
// 出栈
void StackPop(Stack* ps)
{
if(ps->size == 0)
return ;
ps->size--;
}
由于size就代表有效元素个数,我们直接用就行。
6.销毁栈
// 销毁栈
void StackDestroy(Stack* ps)
{
if(ps->_a)
{
free(ps->_a);
ps->_a = NULL;
ps->size = 0;
ps->_capacity = 0;
}
}
销毁栈就和原先顺序表的销毁是一样的。
栈的应用场景
栈由于其后进先出的特性,我们可以用它做一些匹配问题,例如符号匹配问题。
源码
Stack.h
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* _a;
int _top; // 栈顶
int size;//有效数据个数
int _capacity; // 容量
}Stack;
void CheckCapacity(Stack* ps);
// 初始化栈
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);
Stack.c
#include"Stack.h"
#define DEFSTACKSIZE 100
void CheckCapacity(Stack* ps)
{
if(ps->size >= ps->_capacity)
{
ps->_capacity *= 2;
ps->_a = (STDataType *)realloc(ps->_a,ps->_capacity*sizeof(STDataType));
}
}
// 初始化栈
void StackInit(Stack* ps)
{
ps->_a = (STDataType *)calloc(DEFSTACKSIZE,sizeof(STDataType));
ps->_capacity = DEFSTACKSIZE;
ps->size = 0;
}
// 入栈
void StackPush(Stack* ps, STDataType data)
{
CheckCapacity(ps);
ps->_a[ps->size] = data;
ps->size++;
}
// 出栈
void StackPop(Stack* ps)
{
if(ps->size == 0)
return ;
ps->size--;
}
// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
if(ps->size == 0)
return (STDataType)0;
return ps->_a[ps->size-1];
}
// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
return ps->size;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps)
{
return ps->size == 0;
}
// 销毁栈
void StackDestroy(Stack* ps)
{
if(ps->_a)
{
free(ps->_a);
ps->_a = NULL;
ps->size = 0;
ps->_capacity = 0;
}
}