队列中取最大值操作问题

问题:设计一个队列能够在O(1)时间内取得队列的最大值。

分析:

这个问题和设计一个在O(1)时间内取最大值的堆栈看似比较相似,但实现难度要比最大值的堆栈困难一些,开始想模仿最大值堆栈的思想来设计取最大值的堆栈都失败了。实际上这个问题可以拆分成两个问题:

 1)设计一个在O(1)时间内取最大值的堆栈;

 2)如何使用堆栈来实现一个队列;

如果这两个问题解决了,O(1)时间取最大值的队列也就解决了,这体现了把一个困难的问题,分解为几个比较简单的问题,分步骤处理的思想。

    首先看第一个问题:设计一个在O(1)时间内取最大值的堆栈是比较容易的,我们可以使用两个堆栈来保存数据,其中一个保存正常的数据,另一个保存最大值,最大值堆栈在压栈前需要比较待压栈的元素与栈顶元素的大小,如果比栈顶大,那么是一个新的最大值,应该压入栈,否则保持当前最大值不变,也就是不压栈。弹出数据时,如果弹出的值和最大值栈的栈顶元素相同,说明最大值被弹出,此时最大值栈也应该跟着出栈,这样可以保持最大值的更新。

    再看第二个问题,可以使用两个栈来实现一个队列,队列push时,将数据压入A栈中,Pop数据时,如果B栈为空,将A栈的数据Pop出来,压入B栈中,再Pop B栈的数据;当队列Pop时,如果B栈的数据不为空,则直接Pop B栈的数据。

    取队列的Max就是取A栈和B栈的Max,而A、B栈都是我们刚才实现的最大值栈,他们取最大值的时间都是O(1),因此队列取最大值复杂度也是O(1)。但实现是要注意A、B栈有可能为空,在我们的实现中,对于空栈取最大值是未定义的,因此在对A、B栈取最大值时要先判断是否为空栈。

   最后从复杂度来说,队列的Pop操作最坏情况是将A栈的数据都压入B栈,在Pop B栈的数据,最差是O(n),实际多数情况都是O(1)。

   总结一下:这个问题,非常明显的体现了如何将一个新问题转成两个已知的简单问题,同时MaxStack的实现封装了复杂性,使得后面的实现更加简单。

代码如下:

 

[cpp] view plaincopy

  1. #include <stdio.h>  
  2. #include <queue>  
  3. #include <stack>  
  4. template<typename T>  
  5. class MaxStack {  
  6.  public:  
  7.   void Push(const T& value) {  
  8.     data_.push(value);  
  9.     if (max_element_.empty()) {  
  10.       max_element_.push(value);  
  11.     } else if (value >= max_element_.top()) {  
  12.       max_element_.push(value);  
  13.     }  
  14.   }  
  15.   T Top() {  
  16.     return data_.top();  
  17.   }  
  18.   void Pop() {  
  19.     if (data_.top() == max_element_.top()) {  
  20.       max_element_.pop();  
  21.     }  
  22.     data_.pop();      
  23.   }  
  24.   bool Empty() {  
  25.     return data_.empty();  
  26.   }  
  27.   T Max() {  
  28.     if (!max_element_.empty()) {   
  29.       return max_element_.top();  
  30.     }  
  31.   }  
  32.  private:  
  33.   std::stack<T> data_;  
  34.   std::stack<T> max_element_;  
  35. };  
  36. template<typename T>  
  37. class MaxQueue {  
  38.  public:  
  39.   void Push(const T& value) {  
  40.     push_stack_.Push(value);  
  41.   }  
  42.   T Front() {  
  43.     if (pop_stack_.empty()) {  
  44.       while (!push_stack_.Empty()) {  
  45.         pop_stack_.Push(push_stack_.Top());  
  46.         push_stack_.Pop();  
  47.       }  
  48.     }  
  49.     return pop_stack_.Top();  
  50.   }  
  51.   void Pop() {  
  52.     if (pop_stack_.Empty()) {  
  53.       while (!push_stack_.Empty()) {  
  54.         pop_stack_.Push(push_stack_.Top());  
  55.         push_stack_.Pop();  
  56.       }  
  57.     }  
  58.     pop_stack_.Pop();  
  59.   }  
  60.   bool IsEmpty() {  
  61.     return push_stack_.Empty() && pop_stack_.Empty();  
  62.   }  
  63.   T Max() {  
  64.     if (!push_stack_.Empty() && !pop_stack_.Empty()) {  
  65.       return push_stack_.Max() > pop_stack_.Max() ? push_stack_.Max() : pop_stack_.Max();  
  66.     } else if (push_stack_.Empty() && !pop_stack_.Empty()) {  
  67.       return pop_stack_.Max();  
  68.     } else if (!push_stack_.Empty() && pop_stack_.Empty()) {  
  69.       return push_stack_.Max();  
  70.     } else {  
  71.       //      throw RUNTIME_ERROR;  
  72.     }  
  73.   }  
  74.  private:  
  75.   MaxStack<T> push_stack_;  
  76.   MaxStack<T> pop_stack_;  
  77. };  
  78. int main(int argc, char** argv) {  
  79.   MaxQueue<int> max_queue;  
  80.   max_queue.Push(1);  
  81.   max_queue.Push(2);  
  82.   max_queue.Push(6);  
  83.   max_queue.Push(4);  
  84.   max_queue.Push(5);  
  85.   max_queue.Push(2);  
  86.   printf("max %d\n", max_queue.Max());  
  87.   max_queue.Pop();  
  88.   printf("max %d\n", max_queue.Max());  
  89.   max_queue.Pop();  
  90.   printf("max %d\n", max_queue.Max());  
  91.   max_queue.Pop();  
  92.   printf("max %d\n", max_queue.Max());  
  93.   max_queue.Pop();  
  94.   printf("max %d\n", max_queue.Max());  
  95.   max_queue.Pop();  
  96.   printf("max %d\n", max_queue.Max());  
  97. }  

#include "stdafx.h"

const int MAXN = 100;

  

class stack

{

public:

    stack()

    {

        stackTop = -1;

        maxItemIndex = -1;

    }

    void Push(int x)

    {

        stackTop ++;

        if(stackTop >= MAXN)

            ;

        else

        {

            items[stackTop]=x; //添加的新元素放在这个数组中

            if(x>Max())

            {

                nextMaxItem[stackTop] = maxItemIndex; //可以知道最大值元素的前一个元素的索引是多少

                maxItemIndex = stackTop; //x是最大值了,把索引存在最大值索引上

            }

            else

                nextMaxItem[stackTop] = -1;

        }

    }

    int Pop()

    {

        int x;

        if(stackTop < 0)

            return -1;

        else

        {

            x = items[stackTop];

            if(stackTop == maxItemIndex)

            {

                maxItemIndex = nextMaxItem[stackTop];

            }

            stackTop--;

        }

        return x;

    }

    int Max()

    {

        if(maxItemIndex >= 0) //返回数组的元素的最大值,是通过最大值的索引得到

            return items[maxItemIndex];

        else

            return -1;

    }

    bool empty()

    {

        return stackTop == -1;

    }

  

private:

    int items[MAXN];

    int stackTop;

    int nextMaxItem[MAXN];

    int maxItemIndex;

  

};

  

class Queue

{

public:

    void Enqueue(int x)

    {

        B.Push(x);

    }

    int Dequeue()

    {

        if(A.empty())

        {

            while(!B.empty())

            {

                A.Push(B.Pop()); //是为了实现先进先出的原则,先把b的元素弹出,再压入到a中,下一步再把a的元素弹出

            }

        }

        return A.Pop();

    }

    int Max()

    {

        if(A.Max() >= B.Max())

            return A.Max();

        else

            return B.Max();

    }

private:

    stack A;

    stack B;

};

  

int _tmain(int argc, _TCHAR* argv[])

{

  

    Queue q;

    q.Enqueue(10);

    q.Enqueue(100);

    q.Dequeue();

    q.Enqueue(5);

    printf("%d", q.Max());

    return 0;

}

 

posted @ 2013-06-25 16:37  夜雨阑珊  阅读(663)  评论(0编辑  收藏  举报