堆栈

抽象数据类型

(重定向自堆疊

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

「堆栈」的各地常用名稱
中国大陸堆栈、栈
臺灣堆疊
堆疊的简单示意图

操作编辑

堆疊使用兩種基本操作:推入(压栈,push)和彈出(弹栈,pop):

  • 推入:將資料放入堆疊頂端,堆疊頂端移到新放入的資料。
  • 彈出:將堆疊頂端資料移除,堆疊頂端移到移除後的下一筆資料。

特点编辑

堆栈的基本特点:

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

抽象定义编辑

以下是堆栈的VDM(Vienna Development Method英语Vienna Development Method):[1]

函数签名:

  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;elsereturn 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;}elsereturn 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");}

[2]

串列堆疊编辑

存储结构编辑

/* 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;elsereturn 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;}elsereturn 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");}

[2]堆棧有時候也常用來指代堆棧段

硬件堆栈编辑

架构层次上的堆栈通常被用以申请和访问内存。

硬件支持编辑

大多数CPU都有用作堆栈指针的寄存器。

堆疊的應用编辑

参考文献编辑

  1. ^ Jones: "Systematic Software Development Using VDM"
  2. ^ 2.0 2.1 高一凡. 《数据结构》算法实现及解析 2004年10月第2版. 西安: 西安电子科技大学出版社. ISBN 9787560611761 (中文). 

参见编辑

🔥 Top keywords: Baike: 首页Special:搜索九龍城寨之圍城胖猫跳江事件Energy (組合)淚之女王背着善宰跑逆天奇案2金智媛习近平郭葦昀金秀賢 (男演員)不夠善良的我們九龍寨城邊佑錫伍允龍春色寄情人劉俊謙 (香港)張書偉怪獸8號虽然不是英雄葉乃文謝坤達神耆小子六四事件我的婆婆怎麼那麼可愛排球少年!!角色列表唐振剛2024年湯姆斯盃Seventeen (組合)蕭景鴻排球少年!!WIND BREAKER—防風少年—安東尼·愛德華茲 (籃球運動員)ILLIT中华人民共和国中華民國BABYMONSTER與鳳行張文傑BOYNEXTDOOR彭丽媛笑看風雲日本母亲节习明泽金惠奫徐巧芯從Lv2開始開外掛的前勇者候補過著悠哉異世界生活德雷克 (歌手)搜查班長1958支配物种乘風2024張員瑛承欢记嚴爵香港梅龍高速公路塌陷事故柯建銘葬送的芙莉蓮迷宮飯轉生貴族憑鑑定技能扭轉人生~繼承弱小領土後,招募優秀人才打造最強領土~为人民服务 (2022年电影)黃道十二宮IVE (組合)草榴社区歐倩怡沒有秘密周雨彤柯佳嬿無職轉生~到了異世界就拿出真本事~謝京穎埃马纽埃尔·马克龙破墓周處除三害 (電影)許瑋甯Twitter五月天打天下2逆天奇案李主儐大谷翔平家族榮耀之繼承者胡子彤郭晉安毛泽东Baike: 分類索引沈伯洋白紙運動文化大革命城市猎人 (2024年电影)2024年花蓮地震(G)I-DLE城市猎人朴成焄郭宁宁2024年優霸盃哥吉拉-1.0汤姆斯杯