了解一下栈结构
栈
本文部分截图来自王道考研
书籍参考:[1]王晓东.数据结构(语言描述)[M].北京:电子工业出版社.2019前言
前言
栈是一种特殊的表,这种表只能在表首进行插入和删除。所以表首对于栈有特殊意义,称为栈顶,表尾称为栈底,不含任何元素的栈称为空栈。可以简单的来说,栈的修改是按后进先出的原则进行,又称为后进先出(Last In First Out)表,简称LIFO表。
假设一个栈$S$中的元素为$a(n),a(n-1),…,a(1)$,则称$a(1)$为栈底元素,$a(n)$为栈顶元素。栈中元素按照$a(1),a(2)…,a(n)$的顺序进栈,第一个进栈的是$a(1)$,接着依次往后,任何时候,出栈的都是栈顶元素$a(n)$。当$n$个不同的元素进栈,出栈元素不同排列的个数则为
$$
\frac{1}{n+1}C_{2n}^n
$$
这个公式称为卡特兰(Catalan)数
InitStack(&S)
:初始化栈,构造一个空栈$S$,分配内存空间。- StackFree(&S)`:销毁栈,销毁并释放栈$S$所占用的内存空间
Push(&S,x)
:进栈,若栈$S$未满,则将$x$加入使之成为新栈顶。Pop(&S,&x)
:出栈,若栈$S$非空,则弹出栈顶元素,并用$x$返回。StackTop(&S,&x)
:读入栈顶元素,若栈$S$非空,则用$x$返回栈顶元素StackEmpty(&S)
:判断一个栈$S$是否为空,若$S$为空,则返回True
,否则False
栈的顺序存储
栈是一个特殊的表,所以可以使用数组来实现栈,用一个数组data存储栈元素,栈底固定在数组的底部,即data[0]为最早的入栈元素
- 代码实现
栈的顺序存储实现
1 | // 栈-顺序存储 |
创建一个size大小的栈,因为刚开始的时候,data[0]
还没存放数据,所以S->top
初始化不能等于$0$,令它等于$-1$
栈顺序存储的基本操作
判断非空
1 | int StackEmpty(Stack S){ |
进栈操作
1 | void Push(Stack S, int x){ |
先判断栈顶指针是否已经达到了栈的最大容量,如果是返回False
。因为入栈了一个元素,所以栈顶指针加1,再令当前栈顶指针的位置等于插入元素$x$。
出栈操作
1 | int Pop(Stack S){ |
令栈顶指针top
减去一位,使得逻辑上进行一个出栈操作,但实际数据还是遗留在内存中。
读栈顶元素
1 | int StackTop(Stack S){ |
因为数组是动态分配的,所以需要写一个释放内存的函数
1 | void StackFree(Stack S){ |
打印栈
1 | void StackPrint(Stack S){ |
在同时使用过多个栈的情况,为了不会栈溢出,通常要给栈分配一个较大的栈空间,但是各个栈在算法运行中,所使用的最大空间很难估计。所以可以使用共享栈来提高栈空间的利用率。
例如两个栈使用同一个数组data[0:n]
,那么利用栈底不变的特性,一个栈底设为0,另一个栈底设为n,分别各自往数组中间延申。这样每一个栈最大的可用空间为$\frac{n}{2}$。
栈的链式存储
如果要用到多个栈的时候,可以使用链表作为栈的存储结构,也就是栈的链式存储,就是用指针来实现栈。这样方式使栈有着动态大小,这种实现方式也被称为链栈
- 代码实现
栈的链式存储实现
1 | // 栈-链式存储 |
首先创建一个栈结点的类型,data
存储栈元素,next
指向下一个结点的指针。使用typedef
创建一个snode
类型的栈结点指针类型SLink
。
再创建一个链栈Stack
,其中结构只有一个栈顶指针,其指针的类型是栈结点指针类型SLink
。
栈链式存储的基本操作
判断非空
1 | int StackEmpty(Stack S){ |
进栈操作
1 | void Push(Stack S, int x){ |
为新结点申请一块内存空间,同时类型设置为栈结点指针类型,将元素x存入data
中,将新结点的下一个结点置为top的下一个结点。因为top的下一个结点是NULL,所以此时结点p的下一个结点也为NULL。这时结点p为栈的栈顶。
出栈操作
1 | int Pop(Stack S){ |
假设栈内结点为$k->q->s->Null$,这时执行出栈操作,这时候的栈顶为$s$,定义一个变量$x$,另它等于栈顶的data
,将出栈元素赋值给x,再函数的结尾处返回。定义一个栈指针类型的结点$p$,另它等于栈顶,所以这个时候栈内就变成这样$k->q->p->Null$。将栈顶指向$p$的下一个结点,也就是$Null$,$k->q->NULL$,最后将$p$占用的结点内存释放。
读栈顶元素
1 | int StackTop(Stack S){ |
打印栈
1 | int StackPrint(Stack S){ |