大话数据结构第四章栈的基本概念与出栈入栈操作

一、栈的顺序存储结构

1.基本概念

栈顶就是表尾。

栈顶是栈插入和删除的地方。

栈就是只允许在表尾进行添加或删除,是顺序存储结构线性表的特例或者说简化。

为什么说是简化呢?相对于顺序存储结构来说栈只允许在表尾插入和删除,而顺序存储结构线性表是可以在任何位置插入和删除的。所以简化了,我固定位置了。

栈或者队列是固定插入和删除的位置的顺序存储结构的线性表。

具体区分:

栈是固定一端的位置进行插入和删除的顺序存储结构的线性表。

队列是将插入和删除分在两端的顺序存储结构的线性表。

队列:在一端添加,在另一端删除。

2.栈的生长方向

假如栈的长度为n,则数组下标范围为0 ~(n-1)

向上生长:入栈时,栈顶元素下标递增,栈底是数组元素0。空栈的判断一般是栈顶指针是否为-1,当然也有另一种栈的实现方法就是以0为空栈的判断依据。

向下生长:入栈时,栈顶元素下标递减,栈底是数组元素n-1。空栈的判断一般是栈顶指针是否为n,当然也有另外一种栈的,实现方法是以n-1为空栈的判断依据。

因为向上生长的栈,入栈1个元素时,栈顶是元素0,空栈时-1;

而向下生长的栈,入栈1个元素时,栈顶为元素n-1,那空栈时就是n了。

第一,向上生长方向,入栈时是递增方向,出栈时是递减。即递增入栈,递减出栈。

(1)向上生长方向的第1种实现方法。——栈顶本身指向有出栈入栈的数据,它是出栈入栈的最后一个数据指向,本身指向出栈入栈的数据。

以栈顶指向-1为空栈,以栈顶指向n-1为栈满。

它入栈push思路:先判断是否栈满(栈顶为n-1),满的话就返回错误。栈没满,栈顶先自增1,再把数据写入栈里。

它出栈pop思路:先判断是否空栈(栈顶为-1),空栈了就没啥可出了,返回错误。否则,先把栈顶内容读出,栈顶指针再自减1。

(2)向上生长方向的第2种实现方法。——数据在栈顶下面,每次入栈出栈栈顶指向事屋顶一样,屋顶下面才是入栈出栈的数据,栈顶本身的指向只是个界限。

以栈顶指向0为空栈,以栈顶指向n为栈满。

它入栈push思路:先判断是否栈满(栈顶为n),满的话就返回错误。栈没满,先把数据写入栈里,之后栈顶才自增1。

它出栈pop思路:先判断是否空栈(栈顶为n),空栈了就没啥可出了,返回错误。否则,栈顶指针先自减1,再把栈顶内容读出。

第二向下生长方向n-0。递减入栈,递增出栈。

以栈顶指向n为空栈,以栈顶指向0为栈满。 它入栈push思路:先判断是否栈满(栈顶为0),满的话就返回错误。栈没满,栈顶先自减1往下移,再把数据写入栈里。 它出栈pop思路:先判断是否空栈(栈顶为0),空栈了就没啥可出了,返回错误。否则,先把栈顶内容读出,栈顶指针再自增1。

以上情况如下图。

当然,还有下面这种情况:

三、链栈

链栈不需要头结点的。

栈顶在链表表头,也就是链表的第一个节点。

3.1有个问题

问题:形参linkstack *S,这个传入之前肯定要定义一个栈顶节点,这个就固定不变了,之更新栈顶top指针就完事了,假如是linkstack a,那么传入push(&a,3),在传入之前是不是要初始化a?

答:要初始化为0。比如

linkstack a={0,0};

push(&a,3);

再问:为啥?linkstack 是个结构体,里面有个链表节点的指针的,这个链表节点的指针变量要赋为0?那这个链表节点指针为零,那它又是个结构体内部有数据域和指针域,也需要全赋为0吧?

答:只是一个指针,地址。指针是一个存储单元,4个字节

答:我明白了,

linkstack a={0,0};

虽然linkstack是个结构体,但是里面就是2个元素:一个是地址变量(指针),一个计数(普通变量)。

定义a的目的是保存链栈的栈顶指针,也就是固定这个a来保存链栈的头结点,那么初始化为0,是指链栈的栈顶的指针为空,就是目前这个链栈为空么,没有链表,所以栈顶指向为空。——还是指针没学好。

3.2顺序栈和链栈

顺序栈和链栈的出栈入栈的时间复杂度都为O(1),因为没有循环。

在空间上,若空间确定就用顺序栈,若不确定就用链栈。

如果使用过程中元素变化不可预料,有时很小,有时非常大,那么最好是用链擒,反之,如果它的变化在可控范围内,建议使用顺序棋会更好一些。

猜你喜欢

转载自blog.csdn.net/yhb1206/article/details/89537437