编程之美读书笔记-队列中取最大值操作问题

来源:互联网 发布:unix环境编程视频 编辑:程序博客网 时间:2024/05/20 23:32
题目:
假设有这样一个拥有3个操作的队列:
1. EnQueue(v):将v加入队列中
2. DeQueue():使队列中的队首元素删除并返回此元素
3. MaxElement:返回队列中的最大元素
设计一种数据结构和算法,让MaxElement操作的时间复杂度尽可能地低。
解析:设队列长度为N。利用一个数组或链表来存储队列元素,MaxElement时间复杂度为O(N);利用最大堆来存储队列元素,MaxElement时间复杂度为O(1),EnQueue和DeQueue时间复杂度为O(log2N)。按照最大堆的思路,寻找一种新的保存队列中元素相对大小关系的指针集合,并且使得更新这个指针集合的时间复杂度更低。由于栈是一个和队列及其相似的数据结构,我们不妨先看看栈。对于栈来讲,Push和Pop操作都是在栈顶完成的,所以很容易维护栈中的最大值,它的时间复杂度为O(1)。
#include<iostream>  using namespace std; #define MAXN 1000class MyStack{private:int stackTop;int maxStackItemIndex;//最大元素的位置int stackItem[MAXN];int link2NextMaxItem[MAXN];//link2NextMaxItem[i]表示仅小于i位置元素的元素所在位置//如果i位置的元素不是当前栈中最大的,这个值就为-1public:  MyStack(){stackTop = -1;maxStackItemIndex = -1;}bool isEmpty(){return stackTop == -1;}bool isFull(){return stackTop == MAXN - 1;}void push(int x) {if (this->isFull()){cout << "the stack is full now." << endl;return;}else{stackItem[++stackTop] = x; if (x > Max()) {link2NextMaxItem[stackTop] = maxStackItemIndex;maxStackItemIndex = stackTop;}elselink2NextMaxItem[stackTop] = -1;}}int pop() {int ret;if (this->isEmpty()){cout << "the stack is empty now." << endl;return INT_MIN;}else {ret = stackItem[stackTop];  if (stackTop == maxStackItemIndex){maxStackItemIndex = link2NextMaxItem[stackTop];}stackTop--;}return ret;}int Max() {if (maxStackItemIndex >= 0) return stackItem[maxStackItemIndex];else return INT_MIN;}};int main() {MyStack mystack;mystack.push(3);mystack.push(4);mystack.push(8);mystack.push(1);mystack.pop();mystack.push(7);cout << mystack.Max() << endl;return 0;}
如果能够用栈有效地实现队列,而栈的Max操作又很容易实现,那么队列的Max操作也就能有效地完成了。考虑用两个栈来实现一个队列,设为栈A和栈B。
#include<iostream>  using namespace std; #define MAXN 1000class MyStack{private:int stackTop;int maxStackItemIndex;//最大元素的位置int stackItem[MAXN];int link2NextMaxItem[MAXN];//link2NextMaxItem[i]表示仅小于i位置元素的元素所在位置//如果i位置的元素不是当前栈中最大的,这个值就为-1public:  MyStack(){stackTop = -1;maxStackItemIndex = -1;}bool isEmpty(){return stackTop == -1;}bool isFull(){return stackTop == MAXN - 1;}void push(int x) {if (this->isFull()){cout << "the stack is full now." << endl;return;}else{stackItem[++stackTop] = x; if (x > Max()) {link2NextMaxItem[stackTop] = maxStackItemIndex;maxStackItemIndex = stackTop;}elselink2NextMaxItem[stackTop] = -1;}}int pop() {int ret;if (this->isEmpty()){cout << "the stack is empty now." << endl;return INT_MIN;}else {ret = stackItem[stackTop];  if (stackTop == maxStackItemIndex){maxStackItemIndex = link2NextMaxItem[stackTop];}stackTop--;}return ret;}int Max() {if (maxStackItemIndex >= 0) return stackItem[maxStackItemIndex];else return INT_MIN;}};class MyQueue{private:MyStack mystackA,mystackB;public:int MaxValue(int x, int y){if (x > y) return x;else return y;}int Max(){return MaxValue(mystackA.Max(), mystackB.Max());}void EnQueue(int v){mystackB.push(v);}int DeQueue(){if (mystackA.isEmpty()){while (!mystackB.isEmpty()) mystackA.push(mystackB.pop());}return mystackA.pop();}};int main() {MyQueue myqueue;myqueue.EnQueue(8);myqueue.EnQueue(3);myqueue.EnQueue(4);myqueue.EnQueue(1);myqueue.DeQueue();myqueue.EnQueue(7);cout << myqueue.Max() << endl;return 0;}
上述代码能够用栈来实现一个队列。出队的时候,如果A堆栈为空,那么把B堆栈的数据弹出并压入A堆栈这个操作不是O(1)的,虽然如此,但从每个元素的角度来看,它被移动的次数最多可能有3次。所以这种方法的平均时间复杂度是线性的。

0 0
原创粉丝点击