您的位置:首页 > 其它

堆栈的顺序存储

2018-03-28 20:10 183 查看
堆栈是一种特殊的线性表,是一种线性结构,只能对栈的顶端做操作,操作有入栈和出栈两种,就是插入和删除。堆栈一定要遵循先进后出(或叫后入先出)原则,就是最后一个进去的元素一定是第一个出来的。那么堆栈要怎么实现?
第一个很简单的方法就是用一个一维数组,因为栈是一种按顺序存储的结构,所以可以用一维数组来存储栈的数据。因为栈有一个特点是后入先出,最后进入的元素最先出来,所以还要有一个数据来存储栈中最后一个元素的位置。所以可以用一个结构体来表示,结构体成员里有一个数组和一个表示位置的变量。



创建好栈之后,接下来是入栈,往里面放入元素。入栈时通常要做些特殊情况判断,比如栈满了的话就不能继续往里面放元素了。入栈的部分可以这样实现:



注意第16行语句是把Ptrp->Top++后,再把X放在数组的Top++的下标位置。
接着是出栈,把栈里的元素放出来。出栈同样要先做特殊判断,如果栈是空的,就无法放出元素:



包括main函数在内的实现代码参考:



小拓展:既然我们可以用一个结构体来表示一个栈,那么如果需要两个栈,我们可以用两个结构体。不过我们有没有更简单的方法来做呢?我们知道栈的数据存储在一维数组中,所以我们可以用一个一维数组来存储两个栈。这样:



设置两个变量Top1和Top2来表示两个栈的下标。堆栈1从数组头开始往后存储,堆栈2从数组结尾开始往前存储。
接下来看入栈和出栈如何操作。首先看入栈:



首先还是特殊情况判断,看数组是否满了。因为堆栈1和堆栈2是分别从数组两段开始往中间存储数据的,所以当数组满时,两个堆栈的Top变量时紧挨着的,所以判断数组是否满了的条件可以是判断if(Top2-Top1)==1。这里引入了一个Choice变量来区分对哪个堆栈进行操作,当Choice等于1时对堆栈1进行操作,当Choice等于2时对堆栈2进行操作。
到出栈:



同样有一个Choice来判断对哪个堆栈进行操作,然后时特殊情况的判断,对于堆栈1,因为堆栈1是从数组头开始存储的,所以堆栈1为空则Top1等于-1;对于堆栈2,堆栈2从数组末尾开始存储,所以堆栈2为空则Top2等于MAXSIZE。出栈时,对于堆栈1,出栈后Ptrp->Top1--,是从右到左的下标递减,而堆栈2是Ptrp->Top2++,从左到右下标递增。

我们知道用数组来存储数据有一个问题就是数组的大小实现要设定好。设定太少了到后面存储数据时会发现数组不够大,设定太大了有可能会浪费内存。所以我们想更好的方法就是用指针来实现堆栈的存储。就像指针实现线性表一样,堆栈也是特殊的线性表,一样可以用指针来实现。那么我们来看看代码如何写。
首先定义一个结构体,就像线性表那样。



然后就要创建堆栈的头结点,用malloc申请一块空间,创建完后我们做个函数来检查下堆栈是否为空。是就会返回1,否则返回0。
 


堆栈创建好后,接着就要往里面插入结点,即存储数据了,注意我们的存储方式和一般普通的单向链表不同,通常我们会把新接入线性表中的数据接到表尾,但在堆栈中我们知道数据的一大特点是先进后出,后入先出。所以数据要怎么放?新数据还是接在链表尾吗?其实我们应该把新的节点接到头指针的后面,这样每次输出时就容易很多,直接输出头指针的Next就可以了。首先看入栈的代码我们应该怎么写:
 


每次新录入一个结点,malloc申请一块空间,接入结点到头结点的下一个结点,方法是先把新节点的Next指向头结点的Next,然后把头结点的Next指向新录入的结点。
入栈后看下出栈又要怎么写?出栈的方式当然就是把入栈的方式倒过来了:
 


首先做特殊情况判断,如果堆栈为空,就无法pop出数据。如果堆栈不为空,pop出结点数据意味着这个结点也会退出线性表,因为退出的结点最后要free掉,所以我们先定义一个该结构体的指针p指向这个要退出的结点,也就是第40行。接着让头结点指向该退出的结点的下一个结点(第41行),再把该退出的结点里的数据赋值给一个变量k,return k来做出pop动作,最后再free掉p就可以了。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线性表 堆栈