查看“︁堆栈”︁的源代码
←
堆栈
跳转到导航
跳转到搜索
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
{{refimprove|time=2020-05-24T05:09:05+00:00}} {{NoteTA |G1 = IT }} {{Redirect|栈|计算机科学中存储有关正在执行的子程序的消息的栈|呼叫堆疊}} {{各地中文名 |cn = 堆栈、栈 |tw = 堆疊 }} [[File:Data stack.svg|thumb|200px|堆疊的简单示意图]] '''堆疊'''(stack)又稱為'''棧'''或'''-{zh-cn:堆叠; zh-tw:堆棧;}-''',是[[计算机科學]]中的一種[[抽象資料型別]],只允許在有序的線性資料集合的一端(稱為堆疊頂端,top)進行加入数据(push)和移除数据(pop)的運算。因而按照[[後進先出演算法|後進先出]](LIFO, Last In First Out)的原理運作,堆疊常用一維[[陣列|数组]]或[[連結串列]]來實現。常與另一種有序的線性資料集合[[佇列]]相提並論。 == 操作 == 堆疊使用兩種基本操作:推入(压栈,push)和彈出(弹栈,pop): * 推入:將資料放入堆疊頂端,堆疊頂端移到新放入的資料。 * 彈出:將堆疊頂端資料移除,堆疊頂端移到移除後的下一筆資料。 上面就是栈最核心的两个基本操作,可以在[https://gallery.selfboot.cn/zh/algorithms/stack 栈的可视化页面]中直观理解这里的操作。<ref>[https://gallery.selfboot.cn/zh/algorithms/stack 栈的可视化页面]: 在线可视化演示栈的各种操作</ref> [[File:栈的操作可视化.png|thumb|栈的操作可视化图片]] == 特点 == 堆栈的基本特点: # 先入后出,后入先出。 # 除头尾节点之外,每个元素有一个前驱,一个后继。 == 抽象定义 == 以下是堆栈的VDM(''{{link-en|Vienna Development Method|Vienna Development Method}}''):<ref>Jones: "Systematic Software Development Using VDM"</ref> 函数签名: init: -> Stack push: N x Stack -> Stack top: Stack -> (N <math display="inline">\cup</math> ERROR) pop: Stack -> Stack isempty: Stack -> Boolean 此处的N代表某个元素(如自然数),而<math display="inline">\cup</math>表示集合求并。 语义: top(init()) = ERROR top(push(i,s)) = i pop(init()) = init() pop(push(i, s)) = s isempty(init()) = true isempty(push(i, s)) = false == 软件堆栈 == 堆栈可以用[[数组]]和[[链表]]两种方式实现,一般为一个堆栈预先分配一个大小固定且较合适的空间并非难事,所以较流行的做法是<code>Stack</code>结构下含一个数组。如果空间实在紧张,也可用链表实现,且去掉[[表头]]。 这里的例程是以[[C語言]]实现的。 === 陣列堆疊 === ==== 存储结构 ==== <syntaxhighlight lang="c" line="1"> /* c3-1.h 栈的顺序存储表示 */ #define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */ #define STACK_INCREMENT 2 /* 存储空间分配增量 */ typedef struct SqStack { SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */ SElemType *top; /* 栈顶指针 */ int stacksize; /* 当前已分配的存储空间,以元素为单位 */ }SqStack; /* 顺序栈 */ </syntaxhighlight> ==== 基本操作 ==== <syntaxhighlight lang="c" line="1"> /* 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"); } </syntaxhighlight> <ref name="#1"> {{Cite book | author = 高一凡 | editor = | title = 《数据结构》算法实现及解析 | location = 西安 | publisher = 西安电子科技大学出版社 | date = | edition = 2004年10月第2版 | pages = | ISBN = 9787560611761 | accessdate = | url = | language = zh | quote = }} </ref> === 串列堆疊 === ==== 存储结构 ==== <syntaxhighlight lang="c" line="1"> /* c2-2.h 线性表的单链表存储结构 */ struct LNode { ElemType data; struct LNode *next; }; typedef struct LNode *LinkList; /* 另一种定义LinkList的方法 */ </syntaxhighlight> ==== 基本操作 ==== <syntaxhighlight lang="c" line="1"> /* 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线性表 */ } </syntaxhighlight> ==== 链表基本操作 ==== <syntaxhighlight lang="c" line="1"> /* 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"); } </syntaxhighlight> <ref name="#1"/> 堆棧有時候也常用來指代[[堆棧段]]。 == 硬件堆栈 == 架构层次上的堆栈通常被用以申请和访问内存。 === 硬件支持 === 大多数[[CPU]]都有用作堆栈指针的寄存器。 == 堆疊的應用 == * [[回溯法|回溯法]] * [[递归]] * [[深度优先搜索|深度優先搜尋]] == 参考文献 == {{Reflist}} == 参见 == {{Portal|计算机科学}} * [[連結串列]] * [[佇列]] {{-}} {{Data structures}} {{Authority control}} {{DEFAULTSORT:Stack}} [[Category:数据结构]] [[Category:抽象数据类型]] [[Category:带有伪代码示例的条目]]
该页面使用的模板:
Template:-
(
查看源代码
)
Template:Authority control
(
查看源代码
)
Template:Cite book
(
查看源代码
)
Template:Data structures
(
查看源代码
)
Template:Link-en
(
查看源代码
)
Template:NoteTA
(
查看源代码
)
Template:Portal
(
查看源代码
)
Template:Redirect
(
查看源代码
)
Template:Refimprove
(
查看源代码
)
Template:Reflist
(
查看源代码
)
Template:各地中文名
(
查看源代码
)
返回
堆栈
。
导航菜单
个人工具
登录
命名空间
页面
讨论
不转换
查看
阅读
查看源代码
查看历史
更多
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
特殊页面
工具
链入页面
相关更改
页面信息