• 包含min函数的栈和两个栈实现一个队列


    题目:定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。要求函数min、push以及pop的时间复杂度都是O(1)。

    分析:这是google的一道面试题。

    看到这道题目时,第一反应就是每次push一个新元素时,将栈里所有逆序元素排序。这样栈顶元素将是最小元素。但由于不能保证最后push进栈的元素最先出栈,这种思路设计的数据结构已经不是一个栈了。在栈里添加一个成员变量存放最小元素(或最小元素的位置)。每次push一个新元素进栈的时候,如果该元素比当前的最小元素还要小,则更新最小元素。

    乍一看这样思路挺好的。但仔细一想,该思路存在一个重要的问题:如果当前最小元素被pop出去,如何才能得到下一个最小元素?因此仅仅只添加一个成员变量存放最小元素(或最小元素的位置)是不够的。我们需要一个辅助栈。每次push一个新元素的时候,同时将最小元素push到辅助栈中(考虑到元素可能是复杂的数据类型,用位置将能减少空间消耗);每次pop一个元素出栈的时候,同时pop辅助栈。

    参考代码:

    #include <deque>
    #include <assert.h>
    
    template <typename T> 
    class CStackWithMin
    {
    public:
          CStackWithMin(void) {}
          virtual ~CStackWithMin(void) {}
    
          T& top(void);
          const T& top(void) const;
    
          void push(const T& value);
          void pop(void);
    
          const T& min(void) const;
    
    private:
         deque<T> m_data;               // the elements of stack
         deque<size_t> m_minIndex;      // the indices of minimum elements
    };
    
    // get the last element of mutable stack
    template <typename T> T& CStackWithMin<T>::top()
    {
          return m_data.back();
    }
    
    // get the last element of non-mutable stack
    template <typename T> const T& CStackWithMin<T>::top() const
    {
          return m_data.back();
    }
    
    // insert an elment at the end of stack
    template <typename T> void CStackWithMin<T>::push(const T& value)
    {
          // append the data into the end of m_data
          m_data.push_back(value);
    
          // set the index of minimum elment in m_data at the end of m_minIndex
          if(m_minIndex.size() == 0)
                m_minIndex.push_back(0);
          else
          {
                if(value < m_data[m_minIndex.back()])
                      m_minIndex.push_back(m_data.size() - 1);
                else
                      m_minIndex.push_back(m_minIndex.back());
          }
    }
    
    // erease the element at the end of stack
    template <typename T> void CStackWithMin<T>::pop()
    {
          // pop m_data
          m_data.pop_back();
    
          // pop m_minIndex
          m_minIndex.pop_back();
    }
    
    // get the minimum element of stack
    template <typename T> const T& CStackWithMin<T>::min() const
    {
          assert(m_data.size() > 0);
          assert(m_minIndex.size() > 0);
    
          return m_data[m_minIndex.back()];
    }

      步骤     数据栈      辅助栈        最小值
    1.push 3    3          0             3
    2.push 4    3,4        0,0           3
    3.push 2    3,4,2      0,0,2         2
    4.push 1    3,4,2,1    0,0,2,3       1
    5.pop        3,4,2      0,0,2         2
    6.pop        3,4        0,0           3
    7.push 0   3,4,0      0,0,2         0

    另一道题目:用两个栈实现一个队列的功能。

    要求给出算法和思路!

    答:设2个栈为A,B, 一开始均为空.

    入队:

    若A有空间,将新元素push入栈A;

    若A满则判断B是否有元素,有则无法进队列;若无则将栈A中所有元素依次pop出并push到栈B,将新元素push进A

    出队:

    (1)判断栈B是否为空;

    (2)如果不空,则B的栈顶元素出栈;如果为空,则将栈A中所有元素依次pop出并push到栈B;

    (3)将栈B的栈顶元素pop出;

    两个栈都是空时队列为空

    这样实现的队列入队和出队的平摊复杂度都还是O(1)。

    template<typename T> 
    class CQueue
    {
    public:
        CQueue() {}
        ~CQueue() {}
    
        void appendTail(const T& node);  // append a element to tail
        T deleteHead();   // remove the front element from head and return it
        bool isEmpty();
    
    private:
        stack<T> m_stack1;
        stack<T> m_stack2;
    };
    
    //true if the queue has no elements
    template<typename T>
    bool CQueue<T>::isEmpty()
    {
        return m_stack1.empty() && m_stack2.empty();
    }
    
    // Append a element at the tail of the queue
    template<typename T> 
    void CQueue<T>::appendTail(const T & element)
    {
        // push the new element into m_stack1
        m_stack1.push(element);
    } 
    
    // Delete the head from the queue and return it
    template<typename T> 
    T CQueue<T>::deleteHead()
    {
        // if m_stack2 is empty, and there are some
        // elements in m_stack1, push them in m_stack2
        if(m_stack2.size() <= 0)
        {
            while(m_stack1.size() > 0)
            {
                const T & data = m_stack1.top();
                m_stack1.pop();
                m_stack2.push(data);
            }
        }
    
        // push the element into m_stack2
        assert(m_stack2.size() > 0);
        T data = m_stack2.top();
        m_stack2.pop();
        return data;
    }
  • 相关阅读:
    read()系统调用的流程(转个贴)
    linux kernel reading
    开博第一篇
    让人崩溃的Visual C++ 2005 SP1 Redistributable Package (x86),为啥我下不下来?
    System Call on Linux 2.6 for i386(2) int 0x80与systementer
    http://www.netyi.net/in.asp?id=yuanxianping
    取Insert产生的ID
    递归触发器资料
    Commit Trans和Rollback Trans在有触发器操作时的区别
    转:安全配置SQL Server2000服务器
  • 原文地址:https://www.cnblogs.com/luxiaoxun/p/2622673.html
Copyright © 2020-2023  润新知