栈就是只允许在表尾进行添加或删除,是顺序存储结构线性表的特例或者说简化。
为什么说是简化呢?相对于顺序存储结构来说栈只允许在表尾插入和删除,而顺序存储结构线性表是可以在任何位置插入和删除的。所以简化了,我固定位置了。
向上生长:入栈时,栈顶元素下标递增,栈底是数组元素0。空栈的判断一般是栈顶指针是否为-1,当然也有另一种栈的实现方法就是以0为空栈的判断依据。
向下生长:入栈时,栈顶元素下标递减,栈底是数组元素n-1。空栈的判断一般是栈顶指针是否为n,当然也有另外一种栈的,实现方法是以n-1为空栈的判断依据。
因为向上生长的栈,入栈1个元素时,栈顶是元素0,空栈时-1;
而向下生长的栈,入栈1个元素时,栈顶为元素n-1,那空栈时就是n了。
第一,向上生长方向,入栈时是递增方向,出栈时是递减。即递增入栈,递减出栈。
(1)向上生长方向的第1种实现方法。——栈顶本身指向有出栈入栈的数据,它是出栈入栈的最后一个数据指向,本身指向出栈入栈的数据。
它入栈push思路:先判断是否栈满(栈顶为n-1),满的话就返回错误。栈没满,栈顶先自增1,再把数据写入栈里。
它出栈pop思路:先判断是否空栈(栈顶为-1),空栈了就没啥可出了,返回错误。否则,先把栈顶内容读出,栈顶指针再自减1。
(2)向上生长方向的第2种实现方法。——数据在栈顶下面,每次入栈出栈栈顶指向事屋顶一样,屋顶下面才是入栈出栈的数据,栈顶本身的指向只是个界限。
它入栈push思路:先判断是否栈满(栈顶为n),满的话就返回错误。栈没满,先把数据写入栈里,之后栈顶才自增1。
它出栈pop思路:先判断是否空栈(栈顶为n),空栈了就没啥可出了,返回错误。否则,栈顶指针先自减1,再把栈顶内容读出。
以栈顶指向n为空栈,以栈顶指向0为栈满。 它入栈push思路:先判断是否栈满(栈顶为0),满的话就返回错误。栈没满,栈顶先自减1往下移,再把数据写入栈里。 它出栈pop思路:先判断是否空栈(栈顶为0),空栈了就没啥可出了,返回错误。否则,先把栈顶内容读出,栈顶指针再自增1。
当然,还有下面这种情况:
问题:形参linkstack *S,这个传入之前肯定要定义一个栈顶节点,这个就固定不变了,之更新栈顶top指针就完事了,假如是linkstack a,那么传入push(&a,3),在传入之前是不是要初始化a?
再问:为啥?linkstack 是个结构体,里面有个链表节点的指针的,这个链表节点的指针变量要赋为0?那这个链表节点指针为零,那它又是个结构体内部有数据域和指针域,也需要全赋为0吧?
虽然linkstack是个结构体,但是里面就是2个元素:一个是地址变量(指针),一个计数(普通变量)。
定义a的目的是保存链栈的栈顶指针,也就是固定这个a来保存链栈的头结点,那么初始化为0,是指链栈的栈顶的指针为空,就是目前这个链栈为空么,没有链表,所以栈顶指向为空。——还是指针没学好。
顺序栈和链栈的出栈入栈的时间复杂度都为O(1),因为没有循环。
如果使用过程中元素变化不可预料,有时很小,有时非常大,那么最好是用链擒,反之,如果它的变化在可控范围内,建议使用顺序棋会更好一些。