栈,一种先进后出,后进先出,只允许头结点一端插入和删除的数据结构

复杂度O(1)

  • 空间复杂度:入栈和出栈只需一两个临时变量存储空间,所以空间复杂度O(1)
    • 存储数据需要一个大小为n的数组,并不是说空间复杂度就是O(n),因为n个空间是必须的,无法省掉。所以空间复杂度,是指除了原本的数据存储空间外,算法运行还需要的额外的存储空间
  • 时间复杂度:只在栈顶操作,出栈不会涉及内存的重新申请和数据搬移,所以O(1)。但是出栈,当栈中有空闲时间为O(1),当空间不够时,就重新申请内存和数据搬移,时间复杂度为O(n)。
    • 入栈,最好时间复杂度O(1),最坏O(n),根据时间复杂度摊还分析法:
      为了分析方便,先进行假设和定义:
      1. 栈空间不够时,重新申请一个是原来2倍的数组
        为了简化分析,假设只有入栈操作
      2. 定义不涉及内存搬移的入栈操作,时间复杂度为O(1)
      3. 如果当前栈大小为K,并且有心的数据要入栈时,就需要申请2倍大小的内存,并做k个数据的搬移操作,然后再入栈。但接下来的k-1次入栈,不需要重新申请内存和数据搬移。
        数据结构 -- 栈
      4. 所以这次入栈操作,涉及了k个数据搬移,将k个数据搬移均摊到k次入栈操作,那每个入栈操作只需一个数据搬移,所以入栈操作的均摊时间复杂度为O(1)
      5. 这个例子也说明了,均摊时间复杂度一般都等于最好情况时间复杂度,因为大部分情况下,入栈的时间复杂度为O(1),只有在个别时刻才会退化为O(n),所以把耗时多的入栈操作的时间均摊到其他入栈操作上,平均情况下的耗时就接近于O(1)
支持动态扩容的顺序栈
  • 数组实现的栈,是一个大小固定的栈一旦栈满之后就无法添加数据。链式栈的大小不受限,但要存储next指针,会消耗相当对内存
  • 实现一个支持动态扩容的顺序栈,只需底层依赖一个支持动态扩容的数组,当栈满之后,申请更大的数组,将原来的数据搬移到新数组中
栈在函数调用中的应用
  • 线程是程序执行的基本单位,进程是资源分配的基本单位。操作系统给每个线程分配了一块独立的内存空间,这块内存组织成“栈”这种数据结构,用来存储调用函数的临时变量。每次进入一个函数,就会将临时变量作为一个栈帧入栈,当被函数执行完成,返回之后,将这个函数对应的栈帧出栈。
栈在表达式求值中的应用
  • 编译器通过2个栈来实现的,其中一个保存操作数的栈,一个保存运算符的栈,从左到右遍历表达式,从操作数的栈顶取2个操作符,然后进行计算,再把计算完的结果压入操作数符,继续比较
  • 数据结构 -- 栈
栈在括号匹配中的应用
  • 假设表达式中只包含三种括号,圆括号(),方括号[]和花括号{},并且任意嵌套
  • 用栈解决,用栈来保存未匹配的左括号,从左到右依次扫描字符串,当扫描左括号,则将其压入栈中;当扫描到右括号,从栈顶取出一个左括号。若匹配成功,继续扫描剩下的,当遇匹配不成功,则说明非法。
栈在浏览器的前进和后退功能的应用
  • 使用x和y栈,首次浏览的页面依次压入栈X,当点击后退,X出栈,入到Y栈里;当点击前进按钮,从Y出栈放入X栈中。
    数据结构 -- 栈
  • 点击2次后退
    数据结构 -- 栈

相关文章: