C++构建ADT栈与简单应用
绪论
今天我们要讲的栈其实和先前的链表就某种程度而言本质上是相通的,所以便不再精讲了(其实是因为懒)
在写下这篇博文之前,我的C++其实一直都是连入门的边缘都碰不到的级别,所以很多用的都还是C的语法和思维,为此还因为写错代码而被大佬们批判了一番…
基本概念:栈(Stack)
系统里的栈
在计算机系统中,栈则是一个具有以上属性的动态内存区域。程序可以将数据压入栈中,也可以将数据从栈顶弹出。在i386机器中,栈顶由称为esp的寄存器进行定位。压栈的操作使得栈顶的地址减小,弹出的操作使得栈顶的地址增大。
(百度百科:栈)
嗯,大概就是这样(明白脸)
其实我们今天的重点是数据结构当中的栈啦!
数据结构中的栈
栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
栈(Stack)是限制插入和删除只能在一个位置上进行的表,我们将该操作位置称为栈的顶(Top),我们有关栈的所有操作都要从这里开始
栈ADT有两种基本操作,一种是进栈(Push),一种是出栈(Pop),顾名思义,进栈就是将一个新的数据压入栈中使之成为新的栈顶,出栈则是将栈顶的数据(最后插入的元素)删除
由于栈的特殊操作模式,栈有的时候又被称为后进先出表(LIFO)
对一个空栈进行Push或Pop操作一般被认为是栈ADT的错误,但是当Push时空间用尽则是一个实现错误而并非ADT错误
栈的模式图如下,如图所示,只有顶部元素是可以直接访问的:
(图片来自百度百科)
栈的实现
常见的栈的实现方式有两种:结构体实现和数组实现,前一种是一般情况下比较通用的实现方式,后一种则是在OI当中用的更多
利用基于单链表的ADT接口实现栈
单链表的构造很适合我们用来实现栈,我们可以通过在表的顶端插入来实现Pop,通过删除表的顶端元素实现Push,这样一个简单的栈的模型就构建出来了
我们依然选择用上一篇的老办法,三步走战略。
要注意在C++当中不能直接使用malloc分配类的内存,最好是使用operator new(虽然说本质上还是在使用malloc…这个就不属于本篇讨论的范围了)
一、建立抽象
栈的基本属性便是一个能储存多项数据、数据的增添与删除只能在一个位置的表,这个位置为栈的顶
栈的基本操作只有Pop和Push两种,为了使程序更加人性化,我们照例增添一些功能性操作函数,那么我们所需要实现的其实便只有这七个功能:
1、初始化一个非空栈
2、确定栈当中的项数
3、在栈顶使一个新项入栈
4、在栈顶使一个项出栈
5、检查栈是否为空栈
6、删除一整个栈
7、检索栈顶元素
函数声明如下:
bool IsEmpty(Stack * pStack);
Stack* MakeStack(string _Name,ElementType* sData,int dType);
bool PopStack(Stack ** pTop);
bool PushStack(string sName,ElementType* sData,int dType, Stack ** pTop);
bool ClearStack(Stack ** pTop);
int CheckStack(Stack * pTop);
int DataType(Stack *pStack);
ElementType* DataValue(Stack *pStack);
二、建立接口
为了增强栈的通用性(其实只是闲着无聊),我们选择使用一个共用体(即union,在CPP当中被翻译为联合)来定义栈中元素储存的数据
在创建栈时,通过预先定义好的接口中的数据类型码,我们可以很好的确定要读入的数据类型,以使用共用体不同的成员读入数据
typedef union elementtype{
short int s_int;//0
unsigned short int us_int;//1
int _int;//2
unsigned u_int;//3
long long int ll_int;//4
unsigned long long int ull_int;//5
float _float;//6
double