问题:
假定有这样一个拥有3个操作的队列:
1. EnQueue(v): 将v加入队列中
2. DeQueue(): 使队列中的队首元素删除并返回此元素
3. MaxElement(): 返回队列中的最大值
请设计一种数据结构和算法,让MaxElement()操作的时间复杂度尽可能的低。
分析与解法:
【解法一】
利用一个数组或者链表来存储队列的元素,利用两个指针分别指向队列的队首和队尾。如果采用这种方法,那么MaxElement()操作需要遍历队列中的所有元素。在队列的长度为N的条件下,时间复杂度为O(N)。
【解法二】
利用一个数组或者链表来存储队列的元素,对于队列每个元素构建一个节点(包含在队列中的位置),这些节点构成一个最大堆,因此插入和删除操作都要维护这个最大堆,时间复杂度都是O(LogN),取最大值的复杂度为 O(1)。
【解法三】
使用两个栈来实现队列。
- 取最值:返回A栈的最值和B栈的最值相比后的最值。复杂度O(1)。
- 入队操作:直接入到B栈中。复杂度O(1)。
- 出队操作:如果A栈为空,那么将B栈内容逐个出栈并且逐个入栈到A中,然后A栈出栈,复杂度O(N),实际上是B栈的长度;如果A栈不为空,直接A栈出栈,复杂度为O(1)。
对于这种方法,如果对列的操作时,一连串的入栈,然后是一连串的出栈,那么就是首先不停向B入栈,当需要出栈时,将B栈元素全压入A栈,A出栈一个元素,这一步是N的复杂度,但是此后是不停的从A出栈,这都是O(1)的复杂度。对于这样的情景,就是只有第一个元素出栈的时候,要O(N),复杂度不是很均匀。但是对于每个元素来说,要么入B栈,入A栈,从A栈弹出,即总体是3N,平均下来基本上是O(3)。
代码实现参考博文:
http://blog.csdn.net/caryaliu/article/details/8097209
其中Stack类中代码第34、35行
//将x入栈之前最大元素的下标存入link2NextMaxItem[stackTop]
link2NextMaxItem[stackTop] = maxStackItemIndex;
//最大下标maxStackItemIndex更新为x的下标stackTop
maxStackItemIndex = stackTop;
第53行
//若最大值出栈,则将最大值下标更新为link2NextMaxItem[stackTop]中保存的次大值下标
maxStackItemIndex = link2NextMaxItem[stackTop];//