栈(stack)是限定仅在表尾进行插入和删除操作的线性表。
我们把允许插入和删除的一端称为顶 (top)另一端为底(bottom)不含任何数据元素的栈称为空。又称为后进先出(Last Im First out)的性表简称LIFO结构。
首先它是一个线性表,也就是说,栈元素具有线性关系,即前驱后继关系。只不过它是一种特殊的线性表而已。定义中说是在线性表的表尾进行插入和删除操作,这里表尾是指栈顶,而不是栈底。
它的特殊之处就在于限制了这个线性表的插入和删除位置,它始终只在栈顶进行。这也就使得:栈底是固定的,最先进栈的只能在栈底。
栈的插入操作,叫作进栈,也称压栈、入栈。类似子弹入弹夹,如图所示
栈的删除操作,叫作出栈,也有的叫作弹栈。如同弹夹中的子弹出夹,如图所示。
栈的存储方式有两种:
顺序栈和链栈,即栈的顺序存储和链式存储。
采用顺序存储的栈称为顺序栈,它利用一组地址连续的存储单元存放自栈底到栈顶的元素,同时附设一个指针(top)指示当前栈顶的位置。
采用链式存储的栈称为链栈,链栈便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。通常采用单链表实现,并且所有操作都是在单链表的表头进行的。在本文中主要是介绍了顺序栈下的一些基本操作,关于链栈的实现与单链表类似。
栈的基本操作包括:
1)初始化
2)入栈
3)出栈
4)销毁栈
5)构造一个空栈;
6)置为空栈;
7)返回栈的元素个数,即栈的长度;
8)若栈为空栈,则返回TRUE,否则返回FALSE;
9)若栈为满栈,则返回TRUE,否则返回FALSE;
10)若栈不空,则用pVal返回栈顶元素,并返回OK,否则返回ERROR;
11)若栈不空,则删除栈顶元素,用pval返回其值,并返回OK,否则返回ERROR
详细代码与注释
// 栈.cpp
#include<stdio.h>
#include<stdlib.h> //malloc free malloc申请空间失败的时候返回一个空指针
#include<assert.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status; //状态的重命名规则
#define STACK_INIT_SIZE 10 //初始化栈的大小为10
#define STACKINCREMENT 2 //栈的增容操作
typedef int SElemType; //入栈元素 char类型
typedef struct
{
SElemType* base; // 栈底指针
int top; // 栈顶指针 // int top //0 //-1
int stacksize; // 栈的当前最大容量
}SeqStack;
//构造一个空栈
Status InitStack(SeqStack* ps) //ps指向的是顺序栈的首地址
{
assert(ps != nullptr); //形参是指针 第一步就要断言
ps->top = 0; //
ps->stacksize = STACK_INIT_SIZE; //栈的初始大小
ps->base = (SElemType*)malloc(sizeof(SElemType) * ps->stacksize);//malloc 从堆区申请空间 申请 元素的大小乘以ps所占的大小
if (nullptr == ps->base)
{
return ERROR; //申请空间失败
}
return OK;
}
//销毁栈
void DestroyStack(SeqStack* ps)
{
assert(ps != nullptr);
free(ps->base); //base指的是连续的空间
ps->base = nullptr;
ps->top = 0;
ps->stacksize = 0;
}
//置为空栈
void ClearStack(SeqStack* ps)
{
assert(ps != nullptr);
ps->top = 0;
}
//返回栈的元素个数,即栈的长度
int StackLength(const SeqStack* ps)
{
assert(ps != nullptr);
return ps->top; //top是一个指针 top值是元素的个数
}
//若栈为空栈,则返回TRUE,否则返回FALSE
bool StackEmpty(const SeqStack* ps)
{
assert(ps != nullptr);
return StackLength(ps) == 0; //如果栈的长度为0
}
//若栈为满栈,则返回TRUE,否则返回FALSE
bool StackFull(const SeqStack* ps)
{
assert(ps != nullptr);
return ps->top==ps->stacksize; //栈的长度=ps指向的栈的大小
}
bool IncMem(SeqStack* ps)
{
assert(ps != nullptr);
SElemType* newdata = (SElemType*)realloc(ps->base, sizeof(SElemType) * ps->stacksize * STACKINCREMENT);
if (newdata == nullptr) //realloc会自动管理ps->base的空间
{
return false;
}
ps->stacksize = ps->stacksize * STACKINCREMENT;
ps->base = newdata;
return true;
}
//入栈val , val为栈顶数据元素
Status Push(SeqStack* ps, SElemType val)
{
assert(ps != nullptr); //判断栈满
if (StackFull(ps)&&!IncMem(ps)) //如果栈满
{
return OVERFLOW; //内存溢出
}
ps->top++; //栈顶指针加一
ps->base[ps->top] = val; //将新插入的元素赋值给栈顶空间
return OK;
}
//若栈不空,则用pVal返回栈顶元素,并返回OK,否则返回ERROR
Status GetTop(const SeqStack* ps, SElemType* pval)
{
assert(ps != nullptr&&pval!= nullptr);
if (StackEmpty(ps))
{
return ERROR;
}
*pval = ps->base[ps->top - 1];
return OK;
}
//若栈不空,则删除栈顶元素,用pval返回其值,并返回OK,否则返回ERROR
Status Pop(SeqStack* ps, SElemType* pval)
{
assert(ps != nullptr && pval != nullptr);
if (StackEmpty(ps))
{
return ERROR;
}
*pval = ps->base[--ps->top];
return OK;
}
int main()
{
SeqStack mys;
InitStack(&mys); //对栈进行初始化(构建一个栈)
for (int i = 1; i <= 20; ++i)
{
Push(&mys, i);
}
int x;
while (Pop(&mys, &x) != ERROR)
{
printf("%d \n", x);
}
DestroyStack(&mys);
return 0;
}
链栈
栈的链式存储结构,简称为链栈。
代码以及详细注释
#include<stdio.h>
#include<stdlib.h> // malloc free
#include<assert.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int ElemType;
typedef struct StackNode //栈的节点类型
{
ElemType data;
struct StackNode* next;
}StackNode, * PStackNode; //结点类型 指针类型
typedef struct
{
PStackNode top; //栈顶指针
int cursize; //元素个数
}LinkStack; //链栈
StackNode* Buynode(ElemType val, StackNode* narg = nullptr)
{
StackNode* s = (StackNode*)malloc(sizeof(StackNode));
if (nullptr == s)
{
exit(EXIT_FAILURE);
}
//memset(s, 0, sizeof(StackNode));
s->data = val;
s->next = narg;
return s;
}
void Freenode(StackNode* p)
{
free(p);
}
//构造一个空栈
Status InitStack(LinkStack* ps)
{
assert(ps != nullptr);
ps->cursize = 0;
ps->top = nullptr;
}
//置为空栈
void ClearStack(LinkStack* ps)
{
assert(ps != nullptr);
while (ps->top != nullptr)
{
StackNode* q = ps->top;
ps->top = q->next;
Freenode(q);
}
}
//销毁栈
void DestroyStack(LinkStack* ps)
{
assert(ps != nullptr);
ClearStack(ps);
}
//返回栈的元素个数,即栈的长度
int StackLength(const LinkStack* ps)
{
assert(ps != nullptr);
return ps->cursize;
}
//若栈为空栈,则返回TRUE,否则返回FALSE
bool StackEmpty(const LinkStack* ps)
{
assert(ps != nullptr);
return ps->cursize == 0;
}
//入栈val , val为栈顶数据元素
Status Push(LinkStack* ps, ElemType val)
{
assert(ps != nullptr);
StackNode* s = Buynode(val, ps->top);
ps->top = s;
ps->cursize += 1;
return OK;
}
//若栈不空,则用pVal返回栈顶元素,并返回OK,否则返回ERROR
Status GetTop(const LinkStack* ps, ElemType* pval)
{
assert(ps != nullptr);
if (StackEmpty(ps))
{
return ERROR;
}
*pval = ps->top->data;
return OK;
}
//Status GetTop(const LinkStack *ps,ElemType &val);
//若栈不空,则删除栈顶元素,用pval返回其值,并返回OK,否则返回ERROR
Status Pop(LinkStack* ps, ElemType* pval)
{
assert(ps != nullptr);
if (StackEmpty(ps))
{
return ERROR;
}
*pval = ps->top->data;
StackNode* q = ps->top;
ps->top = q->next;
Freenode(q);
ps->cursize -= 1;
return OK;
}