总述
栈和队列是我们在stl中比较熟悉的容器了,关于它的操作我们虽然有可能会混淆,但是应该很明白有什么操作、能怎么操作。
在数据结构里面,我们学习的重点不是如何使用栈与队列,而是学习这个容器的运行基本原理,为我们日后对容器应用的拓展打下基础。(当然能用stl里面的模板栈还是要用模板栈的,自己写万一写错又不知道该怎么改正了)
栈
栈是一种先进后出的数据使用模式,常见题型为括号匹配、表达式计算、火车的进栈出栈问题
栈与线性表一样,都有顺序存储和链式存储两种,分别称为顺序栈和链栈。
顺序栈
顺序栈的模拟相对于链栈简单很多,也是我比较喜欢的模拟栈的方法。因为这个方法不容易出错,虽然有内存的限制,但是一般而言题目都会给定数的数目,不会造成内存溢出的情况~
但是在一般而言的情况下,链栈虽难,却是可以体现一个人的水平的重要标准。毕竟数组大家都会,然而指针就不一样啦。
顺序栈的定义需要注意的方面有:
- 在出栈时的判空以及在入栈时的判满,否则溢出
- 注意是先进行指针的+1.还是先写入数字。对于每个人的情况不同,顺序也不同,不能盲目背书,要学会活学活用。
- 构造函数的条件为,top=-1/0
顺序栈因为比较简单,基本没有难度,适合新手。
链栈
链栈跟单链表一样,是通过一个模拟点的struct跟一个类所构成的。
其实绝大部分内容跟单链表差不多,但是仍存在不同。
例如:
- 因为只需要在栈顶进行插入和删除的操作,所以不需要头节点就能是一样的操作(我们发现在单链表中有头节点的最大区别在于尾插的不同)。
- 并且进行头插相对于尾插更为简单,(尾插的删除操作需要O(N),但是头插只需要O(1)),一直有头指针指向第一个节点,进行它的插入以及删除即可。
队列
队列是一种先进先出的数据使用方式,常见题型为舞会
队列有顺序队列、循环队列和链队列三种,较为简单的为数组模拟的顺序队列,其次是链队列,我觉得最难的反而是循环队列,但是只要理解了我们也会发现,也没什么大不了的嘛。
顺序队列
顺序队列是用数组模拟的、用两个指针表示队头和队尾的队列,由于其数组最开始的部分一旦释放元素就不会再次使用,所以它的空间利用率较小,一般还是不使用为好。
顺序队列需要注意的问题有:
- 注意队尾指针指向那里
- 注意队头指针指向哪里
- 注意你这样设置时,队列为空、队列满的条件是什么
例如,如果设置队头指针front=0,队尾指针tail=0,从队尾进入元素,先填入数据,在进行tail+1。此时队列为空的条件为tail=top=0,满的条件为tail=maxsize。
循环队列
循环队列最大的好处在于空间的利用,学习了它之后相信我们对取余操作也更加的上手了。
循环队列的设置跟顺序队列相同,但是在放入元素和删除元素上有较大的区别。
区别在于:
- 队头队尾的设置仍为front=tail=0,但是队满时,因为需要浪费一个空间模拟队满,所以条件为(tail+1)%maxsize=front。这是栈慢与下溢的判定条件
- 入队操作此时以及固定,先tail=(tail+1)%maxsize,然后a[tail]=x
- 出队操作:front=(front+1)%maxsize
- 取队头:return a[(front+1)%maxsize];
链队列
链队列也是单链表的子集,操作基本相同
难点在于记住头部当队首简单还是尾部当队首简单
经过计算,头部当队首的话,需要进行的是尾插,插入耗时O(1),删除耗时O(1),因为头部为队尾,删除的是第一个元素。
头部当队首的话,进行头插,插入耗时O(1),删除耗时O(N),因为删除需要尾部删除,每次都需要遍历找到最尾部的前一个点。
学习情况
有现成的栈和队列就不想再模拟了,但是即使如此我们也要模拟啊!!我不能怠惰
倒是没有什么疑问,有的问题在刚刚整理博客的时候倒是思考的差不多了,很开心,写博客是很有好处的!
下节课就要学KMP算法了,有点紧张,当时学习KMP算法的时候,虽然看的明白了一点点,但是啊,果然还是太容易忘了!上次看书的时候一脸懵逼,只知道我学过……对算法的印象可能在于某个十分复杂的跳跃了,悲伤