《数据结构与算法 C语言版》—— 3.1栈

3.1栈

3.1.1栈的抽象数据类型定义

栈(stack)是限定仅在表尾进行插入或删除操作的线性表。表尾端称为栈顶,表头端称为栈底。不含元素的栈称为空栈。由于后进栈的元素先出栈,所以栈又称为后进先出(Last In First Out,LIFO)的线性表。
在日常生活中,有很多后进先出的例子。例如,铁路调度站火车的进出是后进先出,人们脱衣服是后穿先脱等。在程序设计中,也常用栈这样的数据结构,实现与保存数据相反的顺序来使用这些数据。
栈的操作有栈的初始化、判空、进栈、出栈及取栈顶元素等。下面给出栈的抽象数据类型的定义:
ADT Stack {
数据对象:D={ai|ai∈ElemSet,i=1,2,…,n,n≥0}
数据关系:R1={|ai-1,ai∈D,i=2,…,n}。约定an端为栈顶,a1端为栈底。
基本操作:
InitStack(&S)
操作结果:构造一个空栈S。
StackEmpty(S)
初始条件:栈S已存在。
操作结果:若栈S为空栈,则返回TRUE,否则返回FALSE。
Push(&S,e)
初始条件:栈S已存在。
操作结果:插入元素e为新的栈顶元素。
Pop(&S,&e)
初始条件:栈S已存在且非空。
操作结果:删除S的栈顶元素,用e返回其值。
GetTop(S)
初始条件:栈S已存在且非空。
操作结果:返回栈顶元素。
DestroyStack(&S)
初始条件:栈S已存在。
操作结果:栈S被销毁。
}ADT Stack

为了讨论方便,若没有特别说明,则假定ElemType为int类型,使用如下自定义类型语句定义:typedef int ElemType;。

3.1.2栈的表示与实现

由于栈是操作受到限制的线性表,所以栈也有顺序存储和链式存储两种方式。
1.顺序栈
利用顺序存储方式实现的栈称为顺序栈。与顺序表的定义一样,在C语言中栈也用动态分配的一维数组来描述其顺序存储结构。这样做的好处是:在应用过程中,当栈的空间不够使用时可以将其扩大。
顺序栈的类型描述如下:

#defineSTACK_INIT_SIZE 100//存储空间的初始分配量
#defineSTACKINCREMENT 10//存储空间分配增量
typedef int ElemType;
typedef struct{
ElemType *data;
int top;//栈顶指针
int stacksize;
}SqStack;

通常将数组的0下标作为栈底,这样空栈时栈顶指针top=-1;进栈时,栈顶指针加1,即top++;出栈时,栈顶指针减1,即top--。栈操作的示意图如图31所示。

图31a是空栈,图31b只有1个元素,图31c是元素a,b,c,d,e依次入栈后的情况;图31d是元素e,d依次出栈后的情况,出栈的元素还在原先的单元中,但指针top已指向新的栈顶元素。通过这个示意图可以帮助大家深刻理解栈顶指针的作用。
下面给出顺序存储结构中栈的基本操作的实现算法。
(1)栈的初始化
int InitStack(SqStack &s){//构造一个空顺序栈S,其存储空间大小为STACK_INIT_SIZE
s.data=new ElemType[STACK_INIT_SIZE];
if(!s.data)exit(OVERFLOW);//存储分配失败
s.top =-1;//栈空
s.stacksize=STACK_INIT_SIZE;
return OK;
}
(2)进栈操作
int Push(SqStack &s,ElemType e){//将e插入栈顶
ElemType *p;
if(s.top>=s.stacksize-1){//栈满
p=(ElemType )realloc(s.data,(s.stacksize+STACKINCREMENT)sizeof(ElemType));
if(!p)exit(OVERFLOW);//存储分配失败
s.data=p;
s.stacksize=s.stacksize+STACKINCREMENT;
}
s.data[++s.top]=e;
return OK;
}
(3)出栈操作
int Pop(SqStack &s,ElemType &e){//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返

//回ERROR
if(s.top==-1)retur ERROR;
e=s.data[s.top--];
return OK;
}
(4)取栈顶元素
ElemType GetTop(SqStack s){//栈已存在且不为空,返回栈顶元素
if(s.top==-1)return ERROR;
return s.data[s.top];
}
(5)判断栈是否为空栈
int StackEmpty(SqStack s){
if(s.top==-1)return OK;
return ERROR;
}
需要注意的是,对于顺序栈,入栈时应首先判断栈是否满了,栈满的条件是S.top>=S.stacksize-1。栈满时不能入栈,否则将出现空间溢出,引起错误,这种现象称为上溢。解决的办法是追加存储空间。出栈和读取栈顶元素时,应先判断栈是否为空,为空时不能操作,否则将产生错误。通常栈空作为控制转移的条件。
2链栈
用链式存储结构实现的栈称为链栈。通常链栈用单链表表示,因此其结点结构与单链表的结点结构相同。在此用LinkStack表示链栈,即有:
typedef struct node{
ElemType data;
struct node *next;
}StackNode,*LinkStack;
LinkStack top;//top为栈顶指针
因为栈中的主要运算是在栈顶插入、删除,显然将链表的头部作为栈顶是最方便的,而且没有必要像单链表那样为了运算方便附加一个头结点。通常将链栈表示成如图32所示的形式。

下面给出链栈基本操作的实现算法。
(1)置空栈
void InitStack(LinkStack &top){//构建一个空栈,栈顶指针为top
top=NULL;
}
(2)判栈空
int StackEmpty(LinkStack top){//判断栈是否为空栈
if(top==NULL) return OK;
else return ERROR;
}
(3)入栈
int Push(LinkStack &top,ElemType x){
StackNode *s;
s=new StackNode;
if(!s)exit(OVERFLOW);
s->data=x;
s->next=top;
top=s;
return OK;
}
(4)出栈
int Pop(LinkStack &top,ElemType &x){
StackNode *p;
if(top==NULL)return ERROR;
else{
x=top->data;
p=top;
top=top->next;
delete p;
returnOK;
}
}
链栈的入栈操作不需要判断栈是否已满,但出栈操作仍需要判断是否为空栈。

时间: 2024-11-18 12:34:52

《数据结构与算法 C语言版》—— 3.1栈的相关文章

《数据结构与算法 C语言版》—— 3.8习题

前言 "数据结构"是计算机程序设计的重要理论技术基础,是计算机学科的核心课程,也是计算机专业考研的必考课程,同时已成为其他理工科专业的热门课程.学好该课程,不仅对学习后续算法设计.数值分析.操作系统.编译原理等课程有很大帮助,而且在实际中有广泛的用途. 数据结构主要研究数据的各种组织形式以及建立在这些结构之上的各种运算的实现.它不仅为用计算机语言进行程序设计提供了方法性的理论指导,还在一个更高的层次上总结了程序设计的常用方法和常用技巧. "数据结构"课程的特点是概念

《数据结构与算法 C语言版》—— 1.1数据结构的研究对象

1.1数据结构的研究对象 自然界中的许多问题是可以用数学工具进行描述的.例如,造桥中的受力问题可描述为线性方程,人口增长的情况可描述为微分方程.但更多的非数值计算问题无法用数学方程加以描述.因此,解决这类问题的关键不再是数学分析和计算方法,而是要设计出合适的数据结构,才能有效地解决问题.请看以下列举的具体问题.例1学生信息检索系统.当我们需要查找某个学生的有关信息或某个专业的情况时,只要建立了相应的数据结构,按照某种算法编写了程序,就可以实现计算机自动检索.由此,可以在学生信息检索系统中建立一个

《数据结构与算法 C语言版》—— 1.4数据类型与抽象数据类型

1.4数据类型与抽象数据类型 1.4.1数据类型 数据类型是和数据结构密切相关的一个概念,它最早出现在高级程序语言中,用以刻画(程序)操作对象的特性.在用高级程序语言编写的程序中,每个变量.常量或表达式都有一个它所属的确定的数据类型.类型显式或隐含地规定了在程序执行期间变量或表达式所有可能的取值范围,以及在这些值上允许进行的操作.因此,数据类型是一个值的集合和定义在此集合上的一组操作的总称.例如,C语言中的整型变量,其值为某个区间上的整数(依赖于机器),定义在其上的操作为加.减.乘.除和取模等算

《数据结构与算法 C语言版》—— 1.5算法与算法分析

1.5算法与算法分析 算法与程序设计和数据结构密切相关.简单地说,算法是解决问题的策略.规则.方法.算法的具体描述形式很多,但计算机程序是对算法的一种精确描述,而且可在计算机上运行.数据结构的操作的实现方法就是一个算法问题,但该问题是针对数据结构的,是在给定的数据结构上进行的.下面从算法的特性.算法描述.算法性能分析与度量等方面对算法进行介绍. 1.5.1算法 算法(algorithm)是对特定问题求解步骤的一种描述,是指令的有限序列.其中,每个指令表示一个或多个操作.一个算法必须满足以下五个重

《数据结构与算法 C语言版》—— 1.8小结

1.8小结 本章介绍了数据结构的研究对象.基本概念与术语.数据类型和抽象数据类型,以及算法.算法的设计原则.算法效率的衡量方法等.主要内容如下.(1)数据结构的研究对象数据结构是一门讨论"描述现实世界实体的数学模型(非数值计算)及其上的操作在计算机中如何表示和实现"的学科.数据结构的内容包括3个"层次"的5个"要素",如表13所示.(2)基本概念与术语简单地说,数据就是计算机操作的对象的总称.数据元素是数据的基本单位,它是数据中的一个"

《数据结构与算法 C语言版》—— 2.6小结

2.6小结 线性表是整个数据结构课程的重要基础,本章的主要内容如下.一个线性表是由n个数据元素构成的有限序列,其特点是数据元素之间存在着线性关系.在计算机中表示这种关系的两种不同的存储结构是顺序存储结构(顺序表)和链式存储结构(链表).1顺序表顺序表是在内存中用一组地址连续的存储单元依次存储线性表的数据元素,借助数组来实现.顺序表中数据元素之间的逻辑关系通过其"存储位置相邻"来表示.对于顺序表,主要有初始化.建立.销毁.插入.删除.按值查找等基本操作.插入和删除操作约需移动一半的元素

《数据结构与算法 C语言版》—— 2.3线性表的链式表示与实现

2.3线性表的链式表示与实现 线性表的顺序存储结构的特点是逻辑关系上相邻的两个元素在物理位置上也相邻,因此可以随机存取表中任一元素,它的存储位置可用一个简单.直观的公式来表示.然而,从另一方面来看,这个特点也造成了这种存储结构的弱点:在作插入或删除操作时,需移动大量元素.本节我们将讨论线性表的另一种表示方法--链式存储结构,其特点是用一组地址任意的存储单元存储线性表中的数据元素.由于它不要求逻辑上相邻的元素在物理位置上也相邻,因此它没有顺序存储结构所具有的弱点,但同时也失去了顺序表随机存取的特点

《数据结构与算法 C语言版》—— 3.3栈与递归实现

3.3栈与递归实现 3.3.1递归的定义 栈还有一个重要应用是在程序设计语言中实现递归.一个直接调用自己或通过一系列的调用语句间接调用自己的函数,称为递归函数.其中直接调用自己的函数称为直接递归.间接调用自己的函数称为间接递归. 递归是算法设计中最重要的手段.它通常把一个大型的复杂问题转化为一个与原问题相似的规模较小的问题来求解.下面是常见的使用递归的三种情况. (1)定义是递归的 现实中,有许多定义是递归定义的,以n!为例来说明,其定义如下: fact(n)=1n=0//递归终止条件 n*fa

《数据结构与算法 C语言版》—— 1.2数据结构的发展概况

1.3基本概念与术语 计算机科学是研究信息表示和处理的科学,信息在计算机内是用数据表示的.直观地说,数据是用于描述客观事物的数值.字符以及一切可以输入到计算机中并由计算机程序加以处理的符号的集合,是计算机操作的对象的总称. 数据元素是数据的基本单位,它是数据中的一个"个体",如整数"5".字符"N"等.有时,一个数据元素可由若干数据项组成,例如,描述一个学生的信息为一个数据元素,学生信息中的每一项(如姓名.学号等)为一个数据项.数据项是数据的不可