zoukankan      html  css  js  c++  java
  • 栈结构的经典算法题

    栈结构

    颠倒一个栈的元素顺序

    问题:假设有一个栈{1,2,3,4,5,6},6是栈顶,1是栈底,现在要把这个栈中的元素颠倒一下。

    思路:最简单的办法当然是把栈中的元素依次pop到一个数组中,然后把这个数组再push回栈里面即可,但这样需要O(n)的辅助空间。

    下面介绍一种仅使用O(1)辅助空间的算法,我们知道,可以使用递归来模拟栈的操作。我们借助函数递归pop元素,这样在递归的函数栈上依次有

    {6,5,4,3,2,1},1是栈顶,6是栈底,然后在递归返回的时候,如何把当前元素塞到原栈的底部呢?这里借助了另一个递归!

    C++代码实现如下:

    void Add2Bottom(stack<int> &s, int val)
    {
        int top;
    
        if (s.empty()) {
            s.push(val);
    
        } else {
    
            top = s.top();
    
            s.pop(); 
    
            Add2Bottom(s, val);
    
            s.push(top);
        }   
    }
    
    void Reverse(stack<int> &s) 
    {
        int top;
    
        if (!s.empty()) {
    
            top = s.top();
    
            s.pop();
    
            Reverse(s);
    
            Add2Bottom(s, top);
        }   
    }
    
    int main()
    {
    
        int n;
        int array[6] = {1,2,3,4,5,6};
    
        stack<int> s;
    
        for (n=0; n<6; n++) s.push(array[n]);
    
        Reverse(s);
    
        while (!s.empty()) {
    
            cout<<s.top()<<endl;
            s.pop();
    
        }   
    
    }

    栈的min函数

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

    思路:利用辅助栈,每次对stack push/pop一个元素时,同时也要更新辅助栈(存储最小元素的位置),例如:

     步骤              数据栈            辅助栈                最小值
    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

    C++代码实现:

    #include <deque>
    #include <assert.h>
    #include <iostream>
    
    using namespace std;
    
    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()];
    }

    int main()
    {
    class CStackWithMin<int> stk;

    
    

    stk.push(3);
    cout<<"min="<<stk.min()<<endl;

    
    

    stk.push(4);
    cout<<"min="<<stk.min()<<endl;

    
    

    stk.push(2);
    cout<<"min="<<stk.min()<<endl;

    
    

    stk.push(1);
    cout<<"min="<<stk.min()<<endl;

    
    

    stk.pop();
    cout<<"min="<<stk.min()<<endl;

    
    

    stk.pop();
    cout<<"min="<<stk.min()<<endl;

    
    

    stk.push(0);
    cout<<"min="<<stk.min()<<endl;
    }

     

    栈的push、pop序列

    输入两个整数序列,其中一个序列表示栈的push顺序,判断另一个序列有没有可能是对应的pop顺序。为了简单起见,我们假设push序列的任意两个整数都是不相等的。 

    比如输入的push序列是1、2、3、4、5,那么4、5、3、2、1就有可能是一个pop系列。因为可以有如下的push和pop序列:push 1,push 2,push 3,push 4,pop,push 5,pop,pop,pop,pop,这样得到的pop序列就是4、5、3、2、1。但序列4、3、5、1、2就不可能是push序列1、2、3、4、5的pop序列。

     C++实现:

    int verify(int in[], int out[], int N)
    {
        int n;  
        int m = 0;
        stack<int> s;
            
        for (n=0; n<N; n++) {
    
            s.push(in[n]);    
    
            while (!s.empty()) {
    
                if (s.top() == out[m]) {
                    s.pop();           
                    m++;
    
                } else {
                    break; 
                }   
    
            }   
        }   
    
        return s.empty();
    }
    
    
    int main()
    {
    
        int ret;
        int in[5] = {1,2,3,4,5};
        int out[5] = {4,3,5,1,2};
    
        ret = verify(in, out, 5); 
        cout<<"ret="<< ret<<endl;
    }

    用栈实现队列

    设2 个栈为A和B,A用作入队,B用作出队。
    队满:A满且B不为空;
    队空:A和B都为空;
    入队
    (1) 如果A未满,将新元素push 入栈A;
    (2) 如果A已满,将栈A中所有元素依次pop 出并push 到栈B,然后将元素入栈A;
    出队
    (1) 如果B为空,则将栈A 中所有元素依次pop 出并push 到栈B,然后将元素出栈B;
    (2) 如果B不为空,将栈B 的栈顶元素pop 出;

    C++代码实现:

    bool queue_empty(stack<int> &s1, stack<int> &s2)
    {
        return s1.empty() && s2.empty();
    }
    
    void enqueue(stack<int> &s1, stack<int> &s2, int val)
    {
        s1.push(val);
    }
    
    void dequeue(stack<int> &s1, stack<int> &s2, int &val)
    {
        int top;
    
        if (s2.empty()) {
    
            while (!s1.empty()) {
                top = s1.top();    
                s1.pop();
                s2.push(top);
            }   
        }   
    
        if (!s2.empty()) {
            val = s2.top();
            s2.pop();
    
        } else {
            cout<<"error: queue is empty"<<endl;
        }   
    }
    
    int main()
    {
    
        int n;
        int array[6] = {1,2,3,4,5,6};
    
        stack<int> s1; 
        stack<int> s2; 
    
        for (n=0; n<6; n++) enqueue(s1, s2, array[n]);
    
        while (!queue_empty(s1, s2)) {
    
            dequeue(s1, s2, n);
            cout<<n<<endl;
        }
    
    }

    注意:这里没有考虑栈空间可能满的问题。

    其实,也可以用一个栈来模拟队列结构,仍然是借助递归栈,每次往栈插入元素时,把它塞到栈底,这样就实现了FIFO的队列结构。

    代码如下:

    void enqueue2(stack<int> &s, int val)
    {
        int top;
    
        if (s.empty()) {
            s.push(val);
    
        } else {
    
            top = s.top();
            s.pop();
    
            enqueue2(s, val);
    
            s.push(top); 
        }   
    }
    
    int main()
    {
    
        int n;
        int array[6] = {1,2,3,4,5,6};
    
        stack<int> s;
    
        for (n=0; n<6; n++) enqueue2(s, array[n]); 
    
        while (!s.empty()) {
    
            n = s.top();
            s.pop();
            cout<<n<<endl;
        }   
    }

    用队列实现栈

    设2 个队列为A和B,A用作入队/出队,B用作辅助。
    队满:A满且B不为空;
    队空:A和B都为空;
    入栈:将新元素插入队列A;
    出栈
    (1) 除最后一个元素外,将队列A的元素全部插入到队列B;
    (2) 将队列A的最后一个元素出队;

    (3) 将队列B的元素换回到队列A;

    void stack_pop(queue<int> &q1, queue<int> &q2, int &n)
    {
        int i, head;
    
        while (!q1.empty()) {
    
            head = q1.front();
            q1.pop();
    
            if (q1.empty()) {
                n = head;
    
            } else {
                q2.push(head);
            }
        }
    
    
        while (!q2.empty()) {
            head = q2.front();
            q1.push(head);
            q2.pop();
        }
    }
    
    
    int main()
    {
    
        int n;
        int array[6] = {1,2,3,4,5,6};
    
        queue<int> q1, q2;
    
        for (n=0; n<6; n++) q1.push(array[n]);
    
        while (!q1.empty()) {
            stack_pop(q1, q2, n);
            cout<<n<<endl;
        }
    }
  • 相关阅读:
    Can we call an undeclared function in C++?
    Template Metaprogramming in C++
    Templates and Default Arguments
    Templates and Static variables in C++
    Default Assignment Operator and References
    Advanced C++ | Conversion Operators
    Use of explicit keyword in C++
    When should we write our own assignment operator in C++?
    Copy constructor vs assignment operator in C++
    VMWare关闭beep声
  • 原文地址:https://www.cnblogs.com/chenny7/p/4126910.html
Copyright © 2011-2022 走看看