栈与队列算法题

栈与队列

 

颠倒一个栈的元素顺序

问题:假设有一个栈{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();

    }   

}

 

 

栈的sort函数

 递归实现

template<class T>
void push(stack<T> &s, T val) {
    if (s.empty() || val <= s.top()) {
        s.push(val);
        return;
    }

    T min = s.top();
    s.pop();
    push(s, val);
    s.push(min);
}

template<class T>
void stackSort(stack<T> &s) {
    stack<T> s2;
    while (!s.empty()) {
        push(s2, s.top());
        s.pop();
    }
    s.swap(s2);
}

 

 

 

 

括号匹配

问题:判断一个文本中,括号是否匹配?

思路:从头到尾扫描字符串,每次遇到左括号(如'(', '[', '{')就压入堆栈,如果遇到右括号(如')', ']', '}')就与栈顶元素比较,如果成对,OK,否则判断不匹配。

 

代码如下:

 

#include <iostream>
#include <stack>
#include <set>
#include <string>

using namespace std;

/*
 * vaild return true, else return false
 */
bool judge_bracket(const string & str)
{
    stack<char> st;

    set<char> left;
    set<char> right;

    left.insert('(');
    left.insert('[');
    left.insert('{');

    right.insert(')');
    right.insert(']');
    right.insert('}');

    for (int i=0; i!=str.size(); i++) {

        set<char>::iterator it1 = left.find(str[i]);
        set<char>::iterator it2 = right.find(str[i]);

        if (it1 != left.end()) {        // match left
            st.push(str[i]);

        } else if (it2 != right.end()) {    // match right

            if (st.size() == 0 ) return false;  // stack is empty

            if (str[i] - st.top() <= 2 ) {    // 右括号的ASCII码比其成对的左括号大1或2
                st.pop();

            } else {
                cout << "str[i]=" << str[i] << "top=" << st.top() <<endl;
                return false;
            }
        }
    }

    return true;
}

int main(int argc, char* argv[])
{
    string test_buffer[5] = {"]({[", "({[]})","([)]{}","(()[{}])","{[((()))]([])}"};

    //test
    for (int i=0; i<5; i++)
    {
        cout << "The string is \"" << test_buffer[i] << "\", The result is "
            << (judge_bracket(test_buffer[i]) ? "matched" : "not matched" ) << endl;
    }

    return 0;
}

 

 

 

栈的min函数

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

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

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

 

C++代码实现:

class MinStack {
public:
    /** initialize your data structure here. */
    MinStack() {
        minIndex.push(INT_MAX);
    }

    void push(int x) {
        if (x < minIndex.top()) {
            minIndex.push(x);
        } else {
            minIndex.push(minIndex.top());
        }

        data.push(x);
    }

    void pop() {
        minIndex.pop();
        data.pop();
    }

    int top() {
        if (data.empty()) return INT_MAX;
        return data.top();
    }

    int getMin() {
        return minIndex.top();
    }

private:
    stack<int> data;
    stack<int> minIndex;
};

 

 

栈的max函数

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

这个与栈的min函数实现类似

class MaxStack {
public:
    MaxStack() {
        maxIndex.push(INT_MIN);
    }

    void Push(int x) {
        maxIndex.push(std::max(x, maxIndex.top()));
        data.push(x);
    }

    int Pop() {
        if (data.empty()) return INT_MIN;
        maxIndex.pop();
        int res = data.top();
        data.pop();
        return res;
    }

    int Top() {
        if (data.empty()) return INT_MAX;
        return data.top();
    }

    int Max() {
        return maxIndex.top();
    }

    bool Empty() {
        return data.empty();
    }

private:
    stack<int> data;
    stack<int> maxIndex;
};

 

 

 

 

 

栈的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;
    }
}

 


队列的Max函数

前面提到可以用两个栈实现队列,以及栈的Max函数实现,把这两个组合一下就能实现队列的Max函数,如下

class MaxQueue {
public:
    void EnQueue(int v) {
        stk2.Push(v);
    }

    int DeQueue() {
        if (stk1.Empty()) {
            while (!stk2.Empty()) {
                stk1.Push(stk2.Pop());
            }
        }
        return stk1.Pop();
    }

    int Max() {
        return max(stk1.Max(), stk2.Max());
    }

    bool Empty() {
        return stk1.Empty() && stk2.Empty();
    }

private:
    MaxStack stk1;
    MaxStack stk2;
};

 

posted @ 2014-11-27 18:07  如果的事  阅读(1096)  评论(0编辑  收藏  举报