「」至此。关于计算机科学中存储有关正在执行的子程序的消息的栈，请见「**呼叫堆疊**」。

堆疊的简单示意图
**堆疊**（stack）又稱為**棧**或，是计算机科學中的一種抽象資料型別，只允許在有序的線性資料集合的一端（稱為堆疊頂端，top）進行加入数据（push）和移除数据（pop）的運算。因而按照後進先出（LIFO, Last In First Out）的原理運作，堆疊常用一維数组或連結串列來實現。常與另一種有序的線性資料集合佇列相提並論。

操作
--

堆疊使用兩種基本操作：推入（压栈，push）和彈出（弹栈，pop）：

* 推入：將資料放入堆疊頂端，堆疊頂端移到新放入的資料。
* 彈出：將堆疊頂端資料移除，堆疊頂端移到移除後的下一筆資料。

特点
--

堆栈的基本特点：

1. 先入后出，后入先出。
2. 除头尾节点之外，每个元素有一个前驱，一个后继。

抽象定义
----

以下是堆栈的VDM（*Vienna Development Method（英语：）*）：

函数签名：

```
  init: -> Stack
  push: N x Stack -> Stack
  top: Stack -> (N {\textstyle \cup } ERROR)
  pop: Stack -> Stack
  isempty: Stack -> Boolean
```

此处的N代表某个元素（如自然数），而{\textstyle \cup }表示集合求并。

语义：

```
  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 线性表的单链表存储结构 \*/
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(i<1) /\* i值不合法 \*/
 return ERROR;
 while(j<i&&p) /\* 没到第i个元素，也没到表尾 \*/
 {
 j++;
 p=p->next;
 }
 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(i<1) /\* i值不合法 \*/
 return ERROR;
 s=(LinkList)malloc(sizeof(struct LNode)); /\* 生成新结点 \*/
 s->data=e; /\* 给s的data域赋值 \*/
 if(i==1) /\* 插在表头 \*/
 {
 s->next=\*L;
 \*L=s; /\* 改变L \*/
 }
 else
 { /\* 插在表的其余处 \*/
 while(p&&j<i-1) /\* 寻找第i-1个结点 \*/
 {
 p=p->next;
 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&&j<i-1) /\* 寻找第i个结点，并令p指向其前驱 \*/
 {
 p=p->next;
 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都有用作堆栈指针的寄存器。

堆疊的應用
-----

* 回溯法
* 递归
* 深度優先搜尋

参考文献
----

1. ↑  Jones: "Systematic Software Development Using VDM"
2. 1 2   高一凡.  2004年10月第2版. 西安: 西安电子科技大学出版社. ISBN 9787560611761 （中文）.

参见
--

* 计算机科学主题

* 連結串列
* 佇列


|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 

| * 
* 论
* 编
数据结构 |
| --- |
|  |
| 类型 | 
* 集合
* 容器

 |
|  |
| 抽象类型 | 
* 关联数组
	+ 多重关连数组（英语：）
* 串列
	+ 前向串列
* 堆栈
* 队列
	+ 双端队列
* 优先队列
	+ 双端优先队列
* 集合
	+ 多重集
	+ 併查集
* 可持久化数据结构
	+ 线段树

 |
|  |
| 数组 | 
* 字串
* 位数组
* 环形缓冲器
* 动态数组
* 哈希表
* 哈希数组树（英语：）
* 稀疏矩阵

 |
|  |
| 链（英语：） | 
* 关联表（英语：）
* 链表
* 跳跃列表
* 松散链表（英语：）
* 异或链表

 |
|  |
| 树 | 
* 线段树
* 自平衡二叉查找树
* B树
* 二叉树
	+ AA树
	+ AVL树
	+ 红黑树
	+ 平衡树
	+ 伸展树
	+ 二叉查找树
* 堆
	+ 二叉堆
	+ 左偏树
	+ 二项堆
	+ 斐波那契堆
* R树
	+ R\*树
	+ R+树
	+ 希爾伯特R树（英语：）
* 希尔伯特前缀树
	+ 哈希树

 |
|  |
| 图 | 
* 有向图
* 有向无环图
* 二元决策图
* 无向图
* 确定性非循环有限自动机（英语：）

 |
|  |
| 数据结构术语 |

 |

|  |  |  |
| --- | --- | --- |
| 

|  |  |
| --- | --- |
| 规范控制 編輯維基數據鏈接 | 
* GND: 4808341-0

 |

 |