数据结构--栈
一,如何理解“栈”
关于“栈”,有一个非常贴切的例子,就是一摞叠在一起的盘子。我们平时放盘子的时候,都是从下往上一个一个放;取的时候,我们也是从上往下一个一个地 依次取,不能从中间任意抽出。后进者先出,先进者后出,这就是典型的“栈”结构。
从栈的操作特性上看,栈是一种“操作受限”的线性表,只允许一个在插入和删除数据。
二,如何实现一个“栈”
栈的注意操作包含两个操作,入栈和出栈,即在栈顶插入/删除一个数据。栈用数组实现叫做顺序栈,用链表实现叫做链式栈。其时间复杂度和空间复杂度都是 ,需要说明的是空间复杂度并不是指原本的数据存储空间,而是算法运行还需要额外的存储空间。
三,支持动态扩容的顺序栈
刚才那个基于数组实现的栈,是一个固定大小的栈,也就是说,在初始化栈时需要事先指定栈的大小。当栈满之后,就无法再往栈里添加数据了。尽管链式栈的 大小不受限,但要存储next指针,内存消耗相对较多。所以,如果要实现一个支持动态扩容的栈,我们只需要底层依赖一个支持动态扩容的数组就可以了。当栈满了之后,我们就申请一个更大的数组,将原来的数据 搬移到新数组中。如果当前栈大小为K,并且已满,当再有新的数据要入栈时,就需要重新申请2倍大小的内存,并且做K个数据的搬移操作,然后再入栈。
实际上,支持动态扩容的顺序栈,我们平时开发中并不常用到。支持动态扩容的顺序栈其时间复杂度如图:
也印证了前面讲到的,均摊时间复杂度一般都等于最好情况时间复杂度。因为在大部分情况下,入栈操作的时间复杂度O都是 ,只 有在个别时刻才会退化为O(n),所以把耗时多的入栈操作的时间均摊到其他入栈操作上,平均情况下的耗时就接近 。
四,栈在函数调用中的应用
栈作为一个比较基础的数据结构,应用场景还是蛮多的。其中,比较经典的一个应用 场景就是函数调用栈。 操作系统给每个线程分配了一块独立的内存空间,这块内存被组织成“栈”这种结构,用来存储函数调用时的临时变量。每进入一个函数,就会将临时变量作为一个栈帧入栈,当被调用函数执行完成,返回之后,将这个函数对应的栈帧出栈。例如如下代码:
[code]int main(){ int a=1; int ret=0; int res=0; ret=add(3,5); res=a+ret; return 0; } int add(int x, int y){ int sum=0; sum=x+y; return sum; }
为了清晰地看到这个过程对应的函数栈里出栈、入栈的操作,如下图。图中显示的是,在执行到add()函数时,函数调用栈的情况:
五,栈在表达式求值中的应用
另一个常见的应用场景,编译器利用栈来实现表达式的求值。比如:34+13*9+44-12/3。实际上,编译器就是通过两个栈来实现的。其中一个保存操作数的栈,另一个保存运算符的栈。从左向右遍历表达式,当遇到数字,我们就直接压入操作 数栈;当遇到运算符,就与运算符栈的栈顶元素进行比较。 如果比运算符栈顶元素的优先级高,就将当前运算符压入栈;如果比运算符栈顶元素的优先级低或者相同,从运算符栈中取栈顶运算符,从操作数栈的栈顶取2个操作数,然后进行计算,再把计算完的结果压入操作数栈,继续比较。 我将3+5*8-6这个表达式的计算过程画成了一张图来理解。
- 根据数据的父子关系创建树形结构并实现遍历
- 数据仓库的设计---星形结构和雪花型结构,数据仓库和数据集市
- 数据结构课设--医院排号系统
- 数据结构实验之查找七:线性之哈希表
- 郝斌数据结构 39~44 循环队列需要几个参数来确定及其含义的讲解
- 数据结构之【栈】以及【模板类】基础练习
- 数据结构(20)——统计叶子数
- 栈的应用-迷宫问题-数据结构
- 数据结构(一)
- 02-线性结构1 一元多项式的乘法与加法运算[网易云课堂-数据结构]
- 数据库的连接及三层结构中的业务层及数据处理层的编写
- 【2136】数据结构实验之二叉树的建立与遍历 SDUTOJ
- 数据结构------链表
- Redis 实践2-数据结构
- poj 3580 SuperMemo 数据结构
- 数据结构之并查集小结
- 一下删除MSSQL表所有的数据,但不删除表结构
- 将list数据转换成树型结构
- 数据结构——N皇后放置方法种数
- 数据结构之希尔排序(C语言)