栈
最近系统的复习数据结构,并练习力扣上的题目,为了让自己记忆理解的更深刻一点,想在这里整理一下各部分的知识总结。当然如果能帮助到大家就更好了。今天整理的部分是栈,同时还有一些自己的思考。
一.定义与特点:
从数据结构的角度讲:
栈是一种具有一定约束的线性表,它只能在一端进行插入和删除操作,即栈顶。
最大的特点就是先入后出(LIFO:Last in First out)。
常见的操作就是:建立空栈,入栈,出栈。
与之类似可比较的数据结构,有堆和队列。
具体比较如下表:
数据结构 | 栈 | 队列 | 堆 |
---|---|---|---|
特点 | 先入后出 LIFO | 先进先出FIFO | 优先队列,按优先级求出元素 |
实现方式 | 数组&链表 | 数组&链表 | 树 |
顺序 | 无需排序,依据输入顺序输出 | 无需排序,依据输入顺序输出 | 需要排序,按照优先级排序 |
特殊元素 | 栈顶元素top | 队首&队尾 | 堆顶(大根堆&小根堆,堆顶为最值) |
从操作系统的角度讲:
栈(stack)又名堆栈是操作系统在建立某个进程时或者线程,为这个线程建立的存储区域,其空间分配是由操作系统自动分配释放,在缓存时使用一级缓存,调用时放于存储空间中,用完就释放。在编译的时候可以指定需要的栈的大小,常常用于存储局部变量的值,函数的参数值等等。
区别 | 栈 | 堆 |
---|---|---|
分配空间 | 系统自动分配并回收 | 程序员动态分配并手动删除 |
存放元素 | 局部变量值,函数参数 | 手动分配的连续空间 |
地址顺序 | 由高到低扩展 | 由低到高扩展 |
内存碎片 | 没有 | 当多次调用malloc和free会产生,降低程序效率 |
效率 | 高(操作系统提供的数据结构,提供专门寄存器存储,专门的执行指令) | 低(c++函数库提供的,机制复杂,需要专门算法完成操作 |
ps:顺便记录一下栈溢出的可能原因:
- 局部数组过大,当函数中的数组过大会引起堆栈溢出
- 递归调用的层次太多,递归函数在运行的过程中会有压栈操作,当压栈元素过多会引起堆栈溢出
- 指针和数组越界,例如字符串拷贝没有注意到长度的变化引起堆栈溢出等,此情况最常见
二.与栈密切相关的概念:递归 & 队列 & 堆
常见的模板编程题:
- 栈和队列的关联性:两个栈实现队列,两个队列实现栈(思想一致,一个用于入栈/队列,一个用于出栈/队列,注意两个之间的更新);
- 后缀表达式(逆波兰式):只需要存储操作数即可,对于操作符号进行判断,做相应的操作;
- 树的深度优先遍历DFS(先中后)的非递归实现;
- 单调栈的方式解决问题:一般情况栈是不需要排序的,但是如果题目给出需要排序的情况,可以利用单调栈来实现。利用单调栈实现算法,我们需要考虑单调栈是按照递增方式还是递减方式排序,这个通常依照题目而定。常规的思路是:满足某一条件时始终入栈,直到不满足该条件,需要判断栈顶元素和当前元素的某种特征,再判断是入栈还是其他操作。
编程中的常见问题:
- 栈空:只要每次入栈,都需要判断栈是否为空
- 溢出问题
三.c++中标准模板库STL
对于栈的实现,STL中给出了相应的容器适配器stack,在使用过程中:
- 需要添加头文件
#include <stack>
- 初始化以及相关函数操作:
stack<int> ss;
stack< int, vector<int> > stk; //覆盖基础容器类型,使用vector实现stk
ss.empty(); //判断stack是否为空,为空返回true,否则返回false
ss.size(); //返回stack中元素的个数
ss.pop(); //删除栈顶元素,但不返回其值
ss.top(); //返回栈顶元素的值,但不删除此元素
ss.push(item); //在栈顶压入新元素item
如果再有新的总结,还会补充哒!!欢迎大家在留言区评论,如有错误,也请指正,感谢感谢 ~