(试题)使用两个栈实现一个队列

思路分析

  • 1、首先我们需要明确栈和队列两者的性质。栈是后进先出型,而队列是先进先出型。这是他俩在操作和使用上最明显的区别,那如果我们需要用两个栈来实现一个队列,最重要的一点就是能够使用栈后进先出的性质来实现队列的先进先出。

  • 2、需要实现上述操作的话,便会产生倒栈的操作。所谓倒栈,就是将数据在两个栈之间到来倒腾的操作。和我们在生活中使用两个杯子来回倒水加速热水冷却的过程十分类似。

  • 3、我们将两个栈分别命名为s1和s2。当我们需要入栈的时候,就将数据元素压入s1中;而需要进行出栈操作时,则将s1中的元素一个个弹出,反向压入s2中,再取s2的栈顶元素,之后再将s2中的剩余元素倒入s1中。此为一次倒栈操作。

  • 4、上述行为已经能够完成题目所需,但明显的是,该办法的效率不是很高,特别是在进行出栈操作时,每一步需要进行太多次倒栈操作。那我们便试着优化一下吧。

  • 5、我们可以在执行倒栈操作时,当执行完size-1次弹出及压栈之后,即s1还剩余一个栈底元素时,将此栈底元素直接弹出,而不再压入s2中,可以减少一次压栈操作。

  • 6、而在进行实际操作及测试的过程中,我们知道,并不会单纯的只进行入栈操作或者出栈操作,大多数操作,此两种操作都是交替进行的。所以,我们需要在进行压栈和出栈前,对行为进行一次预判,以防出现意料之外的bug。

  • 7、入队时,我们先行判断s1是否为空。若不为空,则说明s2中没有元素,我们直接将元素压入s1即可;若为空,则说明可能有剩余元素在s2中,我们需要先进行一次倒栈操作将s2中的元素倒入s1中之后,再将新的元素压入s1中。

  • 8、出队时,则先判断s2是否为空。若不为空,则直接弹出s2的栈顶元素即可;若为空,则需要将s1中的所有元素压入s2中之后,再将s2的栈顶元素弹出。


  • 9、综上所述,我们的最终方案是:
    • 入队时,直接将元素压入s1中;
    • 出队时,先判断s2是否为空。若不为空,则直接弹出s2的栈顶元素;若为空,则将s1中的元素一一压入s2中之后,再弹出s2的栈顶元素。

      这里写图片描述

      这里写图片描述

代码实现

template<class T>
class Myqueue
{
public:
    Myqueue()
    {}

    ~Myqueue()
    {}

    void Push(const T& x)
    {
        s1.push(x);
        back_elem = x;
    }

    void Pop()
    {
        if (!s2.empty())
        {
            s2.pop();
        }
        else if (!s1.empty())
        {
            while (!s1.empty())
            {
                s2.push(s1.top());
                s1.pop();
            }
            s2.pop();
        }
        /*else
        {
            cout << "Error!" << endl;
        }*/
    }

    T& Front()
    {
        if (!s2.empty())
        {
            return s2.top();
        }
        else if (!s1.empty())
        {
            while (!s1.empty())
            {
                s2.push(s1.top());
                s1.pop();
            }
            return s2.top();
        }
    }

    T& Back()
    {
        if (!empty())
            return back_elem;
    }

    T Size()
    {
        return s1.size() + s2.size();
    }

    bool empty()
    {
        return (s1.empty()) && (s2.empty());
    }

    void Print()
    {
        if (!s2.empty())
        {
            while (!s2.empty())
            {
                cout << s2.top() << ' ';
                s2.pop();
            }
        }
        if (!s1.empty())
        {
            while (!s1.empty())
            {
                s2.push(s1.top());
                s1.pop();
            }
            while (!s2.empty())
            {
                cout << s2.top() << ' ';
                s2.pop();
            }
        }
        cout << endl;

    }
private:
    stack<T> s1;
    stack<T> s2;
    T back_elem;
};

测试用例

void Test4()
{
    Myqueue<int> s;
    s.Push(1);
    s.Push(2);
    s.Push(3);
    s.Push(4);
    s.Print();


    s.Push(1);
    s.Push(2);
    s.Push(3);
    s.Push(4);
    s.Pop();
    s.Pop();
    s.Print();

    s.Push(1);
    s.Push(2);
    s.Push(3);
    s.Push(4);
    s.Pop();
    s.Pop();
    s.Push(5);
    s.Push(6);
    s.Print();

    s.Push(1);
    s.Push(2);
    s.Push(3);
    s.Push(4);
    s.Pop();
    s.Pop();
    s.Push(5);
    s.Push(6);
    cout << s.Back() << endl;
    cout << s.Front() << endl;
    cout << s.Size() << endl;

}

实现结果

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值