【堆栈】
堆叠的简单示意图
堆叠（stack）又称为栈或-{zh-cn:堆叠; zh-tw:堆栈;}-，是计算机科学中的一种抽象资料型别，只允许在有序的线性资料集合的一端（称为堆叠顶端，top）进行加入数据（push）和移除数据（pop）的运算。因而按照后进先出（LIFO, Last In First Out）的原理运作，堆叠常用一维数组或连结串列来实现。常与另一种有序的线性资料集合伫列相提并论。
== 操作 ==
堆叠使用两种基本操作：推入（压栈，push）和弹出（弹栈，pop）：
* 推入：将资料放入堆叠顶端，堆叠顶端移到新放入的资料。
* 弹出：将堆叠顶端资料移除，堆叠顶端移到移除后的下一笔资料。
== 特点 ==
堆栈的基本特点：
# 先入后出，后入先出。
# 除头尾节点之外，每个元素有一个前驱，一个后继。
== 抽象定义 ==
以下是堆栈的VDM（Vienna Development Method）：
函数签名：
init: -> Stack
push: N x Stack -> Stack
top: Stack -> (N  ERROR)
pop: Stack -> Stack
isempty: Stack -> Boolean
此处的N代表某个元素（如自然数），而表示集合求并。
语义：
top(init()) = ERROR
top(push(i,s)) = i
pop(init()) = init()
pop(push(i, s)) = s
isempty(init()) = true
isempty(push(i, s)) = false
== 软件堆栈 ==
堆栈可以用数组和链表两种方式实现，一般为一个堆栈预先分配一个大小固定且较合适的空间并非难事，所以较流行的做法是Stack结构下含一个数组。如果空间实在紧张，也可用链表实现，且去掉表头。
这里的例程是以C语言实现的。
=== 阵列堆叠 ===
==== 存储结构 ====
/* c3-1.h 栈的顺序存储表示 */
#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */
#define STACK_INCREMENT 2 /* 存储空间分配增量 */
typedef struct SqStack
{
SElemType *base; /* 在栈构造之前和销毁之后，base的值为NULL */
SElemType *top; /* 栈顶指针 */
int stacksize; /* 当前已分配的存储空间，以元素为单位 */
}SqStack; /* 顺序栈 */
==== 基本操作 ====
/* bo3-1.c 顺序栈(存储结构由c3-1.h定义)的基本操作(9个) */
void InitStack(SqStack *S)
{	/* 构造一个空栈S */
(*S).base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
if(!(*S).base)
exit(OVERFLOW); /* 存储分配失败 */
(*S).top=(*S).base;
(*S).stacksize=STACK_INIT_SIZE;
}
void DestroyStack(SqStack *S)
{	/* 销毁栈S，S不再存在 */
free((*S).base);
(*S).base=NULL;
(*S).top=NULL;
(*S).stacksize=0;
}
void ClearStack(SqStack *S)
{	/* 把S置为空栈 */
(*S).top=(*S).base;
}
Status StackEmpty(SqStack S)
{	/* 若栈S为空栈，则返回TRUE，否则返回FALSE */
if(S.top==S.base)
return TRUE;
else
return FALSE;
}
int StackLength(SqStack S)
{	/* 返回S的元素个数，即栈的长度 */
return S.top-S.base;
}
Status GetTop(SqStack S,SElemType *e)
{ /* 若栈不空，则用e返回S的栈顶元素，并返回OK；否则返回ERROR */
if(S.top>S.base)
{
*e=*(S.top-1);
return OK;
}
else
return ERROR;
}
void Push(SqStack *S,SElemType e)
{	/* 插入元素e为新的栈顶元素 */
if((*S).top-(*S).base>=(*S).stacksize) /* 栈满，追加存储空间 */
{
(*S).base=(SElemType *)realloc((*S).base,((*S).stacksize+STACK_INCREMENT)*sizeof(SElemType));
if(!(*S).base)
exit(OVERFLOW); /* 存储分配失败 */
(*S).top=(*S).base+(*S).stacksize;
(*S).stacksize+=STACK_INCREMENT;
}
*((*S).top)++=e;
}
Status Pop(SqStack *S,SElemType *e)
{	/* 若栈不空，则删除S的栈顶元素，用e返回其值，并返回OK；否则返回ERROR */
if((*S).top==(*S).base)
return ERROR;
*e=*--(*S).top;
return OK;
}
void StackTraverse(SqStack S,void(*visit)(SElemType))
{	/* 从栈底到栈顶依次对栈中每个元素调用函数visit() */
while(S.top>S.base)
visit(*S.base++);
printf("\n");
}
=== 串列堆叠 ===
==== 存储结构 ====
/* c2-2.h 线性表的单链表存储结构 */
typedef struct LNode
{
ElemType data;
struct LNode *next;
};
typedef struct LNode *LinkList; /* 另一种定义LinkList的方法 */
==== 基本操作 ====
/* bo3-5.c 链栈(存储结构由c2-2.h定义)的基本操作(4个) */
/* 部分基本操作是由bo2-8.cpp中的函数改名得来 */
/* 另一部分基本操作是由调用bo2-8.cpp中的函数(取特例)得来 */
typedef SElemType ElemType; /* 栈结点类型和链表结点类型一致 */
#include"c2-2.h" /* 单链表存储结构 */
typedef LinkList LinkStack; /* LinkStack是指向栈结点的指针类型 */
#define InitStack InitList /* InitStack()与InitList()作用相同，下同 */
#define DestroyStack DestroyList
#define ClearStack ClearList
#define StackEmpty ListEmpty
#define StackLength ListLength
#include"bo2-8.c" /* 无头结点单链表的基本操作 */
Status GetTop(LinkStack S,SElemType *e)
{	/* 若栈不空，则用e返回S的栈顶元素，并返回OK；否则返回ERROR */
return GetElem(S,1,e);
}
Status Push(LinkStack *S,SElemType e)
{	/* 插入元素e为新的栈顶元素 */
return ListInsert(S,1,e);
}
Status Pop(LinkStack *S,SElemType *e)
{	/* 若栈不空，则删除S的栈顶元素，用e返回其值，并返回OK；否则返回ERROR */
return ListDelete(S,1,e);
}
void StackTraverse(LinkStack S,void(*visit)(SElemType))
{	/* 从栈底到栈顶依次对栈中每个元素调用函数visit() */
LinkStack temp,p=S; /* p指向栈顶元素 */
InitStack(&temp); /* 初始化临时栈temp */
while(p)
{
Push(&temp,p->data); /* 由S栈顶到栈底，依次将栈元素入栈到temp栈 */
p=p->next;
}
ListTraverse(temp,visit); /* 遍历temp线性表 */
}
==== 链表基本操作 ====
/* bo2-8.c 不带头结点的单链表(存储结构由c2-2.h定义)的部分基本操作(9个) */
#define DestroyList ClearList /* DestroyList()和ClearList()的操作是一样的 */
void InitList(LinkList *L)
{	/* 操作结果：构造一个空的线性表L */
*L=NULL; /* 指针为空 */
}
void ClearList(LinkList *L)
{	/* 初始条件：线性表L已存在。操作结果：将L重置为空表 */
LinkList p;
while(*L) /* L不空 */
{
p=*L; /* p指向首元结点 */
*L=(*L)->next; /* L指向第2个结点(新首元结点) */
free(p); /* 释放首元结点 */
}
}
Status ListEmpty(LinkList L)
{	/* 初始条件：线性表L已存在。操作结果：若L为空表，则返回TRUE，否则返回FALSE */
if(L)
return FALSE;
else
return TRUE;
}
int ListLength(LinkList L)
{	/* 初始条件：线性表L已存在。操作结果：返回L中数据元素个数 */
int i=0;
LinkList p=L;
while(p) /* p指向结点(没到表尾) */
{
p=p->next; /* p指向下一个结点 */
i++;
}
return i;
}
Status GetElem(LinkList L,int i,ElemType *e)
{	/* L为不带头结点的单链表的头指针。当第i个元素存在时，其值赋给e并返回OK，否则返回ERROR */
int j=1;
LinkList p=L;
if(inext;
}
if(j==i) /* 存在第i个元素 */
{
*e=p->data;
return OK;
}
else
return ERROR;
}
int LocateElem(LinkList L,ElemType e,Status(*compare)(ElemType,ElemType))
{ 	/* 初始条件：线性表L已存在，compare()是数据元素判定函数(满足为1，否则为0) */
/* 操作结果：返回L中第1个与e满足关系compare()的数据元素的位序。 */
/*           若这样的数据元素不存在，则返回值为0 */
int i=0;
LinkList p=L;
while(p)
{
i++;
if(compare(p->data,e)) /* 找到这样的数据元素 */
return i;
p=p->next;
}
return 0;
}
Status ListInsert(LinkList *L,int i,ElemType e)
{	/* 在不带头结点的单链线性表L中第i个位置之前插入元素e */
int j=1;
LinkList p=*L,s;
if(idata=e; /* 给s的data域赋值 */
if(i==1) /* 插在表头 */
{
s->next=*L;
*L=s; /* 改变L */
}
else
{	/* 插在表的其余处 */
while(p&&jnext;
j++;
}
if(!p) /* i大于表长+1 */
return ERROR;
s->next=p->next;
p->next=s;
}
return OK;
}
Status ListDelete(LinkList *L,int i,ElemType *e)
{	/* 在不带头结点的单链线性表L中，删除第i个元素，并由e返回其值 */
int j=1;
LinkList p=*L,q;
if(i==1) /* 删除第1个结点 */
{
*L=p->next; /* L由第2个结点开始 */
*e=p->data;
free(p); /* 删除并释放第1个结点 */
}
else
{
while(p->next&&jnext;
j++;
}
if(!p->next
j>i-1) /* 删除位置不合理 */
return ERROR;
q=p->next; /* 删除并释放结点 */
p->next=q->next;
*e=q->data;
free(q);
}
return OK;
}
void ListTraverse(LinkList L,void(*vi)(ElemType))
{	/* 初始条件：线性表L已存在。操作结果：依次对L的每个数据元素调用函数vi() */
LinkList p=L;
while(p)
{
vi(p->data);
p=p->next;
}
printf("\n");
}
堆栈有时候也常用来指代堆栈段。
== 硬件堆栈 ==
架构层次上的堆栈通常被用以申请和访问内存。
=== 硬件支持 ===
大多数CPU都有用作堆栈指针的寄存器。
== 堆叠的应用 ==
* 回溯
* 递归
* 深度优先搜寻
== 参考文献 ==