• 队列中取最大值操作问题


    问题:设计一个队列能够在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 ", max_queue.Max());  
    87.   max_queue.Pop();  
    88.   printf("max %d ", max_queue.Max());  
    89.   max_queue.Pop();  
    90.   printf("max %d ", max_queue.Max());  
    91.   max_queue.Pop();  
    92.   printf("max %d ", max_queue.Max());  
    93.   max_queue.Pop();  
    94.   printf("max %d ", max_queue.Max());  
    95.   max_queue.Pop();  
    96.   printf("max %d ", 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;

    }

  • 相关阅读:
    一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
    210902
    1-2
    1-1
    4
    3
    2
    1
    u编码
    windows java 安装版 控制面板
  • 原文地址:https://www.cnblogs.com/fickleness/p/3154961.html
Copyright © 2020-2023  润新知