c++实现任意表达时候求值(栈)并判断表达式的正确性_04 栈、队列

定义

只允许在一端插入和删除数据,后进先出的线性表。

栈既可以用数组实现,也可以用链表来实现。

固定大小的栈

由于操作简单,常规的栈时间复杂度和空间复杂度皆为O(1)。

支持动态扩展的栈

支持动态扩容的栈,其底层其实是用一个支持动态扩容的数组支持的,当栈空间满了以后,我们就申请一个更大的数组,将原来的数据迁移过去。

如果忘了数组是如何支持动态扩展的,可以去下文复习一下。

淤白:02 数组(附ArrayList源码分析)​zhuanlan.zhihu.com
zhihu-card-default.svg

支持动态扩展的栈,其时间复杂度平时是O(1),但当进行扩容的时候,时间复杂度就变为了O(n),利用摊还分析法,我们可知,其平均情况下的时间复杂度为O(1)。

摊还分析法可以在下文中复习一下。

淤白:01 复杂度分析​zhuanlan.zhihu.com
zhihu-card-default.svg

平时开发过程中,遇到的栈操作可能不多,但其实我们可能一直在用到它。例如函数调用(遇到过StackOverflowError的化,可能记忆犹新);还有在表达式求值的时候,其实编译器就是通过栈去实现的。面试中,我们可能也会碰到栈的相关问题:括号匹配,用栈实现队列。


队列

定义

允许在一端插入数据,另一端删除数据,先进先出的线性表。

队列和栈类似,也可以使用数组或者链表实现。

顺序队列(数组实现)

相较于栈的一端操作,只需要一个指针,队列的入队出队需要两个指针head和tail的配合。但这里会碰到一个问题,如果每次出队的时候(类比删除数组元素下标为0的元素),都进行数据前移,那时间复杂度就是O(n)了。下图是进行三次出队的情况。

17a32b06374ecd19edd49f333326ac9d.png

针对这种情况,我们可以用到数组篇聊到的一个方案,延迟前移,只有当入队时发现空间不够了,再进行整体的一个移位,这样均摊下来,时间复杂度也就降下来了。

还有一种解决方案,就是使用循环队列

循环队列

顾名思义,就是将队尾和队首连起来,即当tail指针指向队尾时,再进行入队操作,会将tail指针指向下标为0的位置。通过循环队列,我们就不需要再考虑数据移位的问题,不过实现起来,需要考虑清楚队空和队满的情况。

在非循环队列中,判断队空用的head == tail,队满用的tail == n。

在循环队列中,判断队空仍然可用head == tail,但是队满不能使用tail == n了,而是要用(tail+1) % n == head,可以画图试一下。

队列在实际开发中,用到的会更多一些,比如支持并发的BlockingQueue阻塞队列,用来实现生产者-消费者模型。还有就是双端队列Deque,支持在队首队尾都可以进行入队出队操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值