现在的位置: 首页 > 综合 > 正文

队列中取最大值操作问题

2019年09月30日 ⁄ 综合 ⁄ 共 2821字 ⁄ 字号 评论关闭

问题出处:《编程之美》3.7队列中取最大值操作问题


假定有这样一个拥有3个操作的队列:

1. EnQueue(v): 将v加入队列中

2. DeQueue(): 使队列中的队首元素删除并返回此元素

3. MaxElement(): 返回队列中的最大值

请设计一种数据结构和算法,让MaxElement()操作的时间复杂度尽可能的低。


常规思路:利用一个数组或者链表来存储队列的元素,利用两个指针分别指向队列的队首和队尾。如果采用这种方法,那么MaxElement()操作需要遍历队列中的所有元素。在队列的长度为N的条件下,时间复杂度为O(N).

下面的方法是在编程之美上看到的,能够实现MaxElement()的操作时间复杂度为O(1), 并且入队和出队的操作也很简单。

该队列使用两个栈stackA, stackB来实现的,stack有两个数组:stackItem[ ] 和 link2NextMaxItem[ ], stackItem 用于维护队列中的元素,link2NextMaxItem 用于维护栈中最大值的状态。入队操作是在stackB中执行入栈操作完成,出队操作是用stackA来完成,当stackA中没有元素时,将stackB中的所有元素都pop到stackA中,这样stackB中先入队的元素就会在stackA中的顶部,这样在stackA上执行pop操作,返回的元素就是最先入队的元素。

堆栈的程序描述如下,它实现了堆栈的入栈,出栈,维护栈中最大值状态,栈中元素打印的功能:

#define MAXN    100
class Stack
{
    public:
        //构造函数,初始化堆栈:
        //|stackTop|指向当前堆栈的顶部元素,
        //|maxStackItemIndex|存储当前堆栈中最大元素的index
        Stack(){
            stackTop = -1;
            maxStackItemIndex = -1;
        }

        //判断当前堆栈是否为空
        bool isEmpty() {
            return stackTop == -1;
        }

        //判断当前堆栈是否满
        bool isFull() {
            return stackTop == MAXN - 1;
        }

        //向堆栈中push元素,
        void push(int x) {
            if(this->isFull()) {                //首先检测堆栈空间是否满
                cout<<"the stack is full now."<<endl;
            }
            else {
                stackItem[++stackTop] = x;
                //如果压入堆栈的值比之前记录的最大值大,那么那之前的最大值记录在
                //link2NextMaxItem[stackTop]的位置,把当前最大值在堆栈stackItem
                //中的位置用maxStackItemIndex保存
                if(x > maxValue()) {
                    link2NextMaxItem[stackTop] = maxStackItemIndex;
                    maxStackItemIndex = stackTop;
                }
                else
                    link2NextMaxItem[stackTop] = -1;
            }
        }

        int pop(){
            int ret;
            if(this->isEmpty()) {
                cout<<"the stack is empty."<<endl;
            }
            else {
                ret = stackItem[stackTop];
                //如果pop出的值是当前的最大值,那么则需要将之前保存到link2NextMaxItem[stackTop]
                //中的最大值取出,更新maxStackItemIndex的值
                if( stackTop == maxStackItemIndex )
                {
                    maxStackItemIndex = link2NextMaxItem[stackTop];
                }
            }
            --stackTop;
            return ret;
        }

        //取出堆栈中当前的最大值
        int maxValue(){
            if(maxStackItemIndex >= 0)
                return stackItem[maxStackItemIndex];
            else{
                return INT_MIN;
            }
        }
        void printItems() {
            for (int i = 0; i <= stackTop; ++i) {
                cout<<" "<<stackItem[i];
            }
        }
        void reversePrintItems() {
            for (int i = stackTop; i >= 0; --i) {
                cout<<" "<<stackItem[i];
            }
        }
    private:
        int stackItem[MAXN];
        int stackTop;
        int link2NextMaxItem[MAXN];
        int maxStackItemIndex;
};

使用上面的栈结构的两个栈对象就可以实现队列的结构了,并使MaxElement()操作的时间复杂度为O(1), 程序描述如下:

class Queue
{
    public:
        int maxValue(int x, int y) {
            if(x>y)
                return x;
            else
                return y;
        }

        //返回队列中最大值
        int max() {
            return maxValue(stackA.maxValue(), stackB.maxValue());
        }
        
        void printQueue() {
            stackA.reversePrintItems();
            stackB.printItems();
            cout<<endl;
        }

        //在队列末尾插入元素
        void insertQueue(int x) {
            stackB.push(x);
        }

        //删除并返回队首元素,
        //如果stackA中是空,则先将stackB中的所有元素pop到stackA中,
        //这样stackB中先插入的元素就会pop到stackA中的顶部
        int deQueue() {
            if(stackA.isEmpty()) {
                while(!stackB.isEmpty())
                    stackA.push(stackB.pop());
            }
            return stackA.pop();
        }
    private:
        Stack stackA;    //维护出队列操作
        Stack stackB;    //维护入队列操作
};

调试代码如下:

int main()
{
    Queue queue;
    int a[] = {909, 2, 3, 4, 9, 4, 5, 10, 6};
    for(int i = 0; i < sizeof(a)/sizeof(int); ++i) {
        queue.insertQueue(a[i]);
    }
    queue.insertQueue(101);
    cout<<"queue maxvalue = "<<queue.max()<<endl;
    queue.insertQueue(590);
    cout<<"queue maxvalue = "<<queue.max()<<endl;
    queue.printQueue();
    int deq = queue.deQueue();
    cout<<"deq = "<<deq<<endl;
    cout<<"queue maxvalue = "<<queue.max()<<endl;
}

当前得自己加上头文件。

我的微博:http://weibo.com/caryaliu

抱歉!评论已关闭.