用栈实现队列

问题分析

用栈实现队列等价于 "后进先出" 的特性实现 "先进先出" 的特性!

解决方案设计

image.png

实现思路

准备两个栈用于实现队列: stack_in 和 stack_out

  • 当有新元素入队时:将其压入 stack_in
  • 当需要出队时:

    • stack_out() == 0 :
    • 将 stack_in 中的元素逐一弹出并压入 stack_out
  • stack_out.size() > 0 :

    • 将 stack_out 的栈顶元素弹出

编程实验:用栈实现队列

文件:StackToQueue.h

#include <iostream>
#include "LinkStack.h"
#include "Queue.h"

using namespace std;
using namespace DTLib;

template <typename T>
class StackToQueue : public Queue<T>
{
public:
    void add(const T &e) override  // O(1)
    {
        m_stack_in.push(e);
    }

    void remove() override  // O(n)
    {
        move();

        if (m_stack_out.size() > 0)
        {
            m_stack_out.pop();
        }
        else
        {
            THROW_EXCEPTION(InvalidOpertionExcetion, "No element in current StackToQueue ...");
        }
    }

    T front() const override  // O(n)
    {
        move();

        if (m_stack_out.size() > 0)
        {
            return m_stack_out.top();
        }
        else
        {
            THROW_EXCEPTION(InvalidOpertionExcetion, "No element in current StackToQueue ...");
        }
    }

    void clear() override  // O(n)
    {
        m_stack_in.clear();
        m_stack_out.clear();
    }

    int length() const override  // O(1)
    {
        return m_stack_in.size() + m_stack_out.size();
    }

    ~StackToQueue() override // O(n)
    {
        clear();
    }

protected:
    mutable LinkStack<T> m_stack_in;
    mutable LinkStack<T> m_stack_out;

    void move() const // O(n)
    {
        if (m_stack_out.size() == 0)
        {
            while (m_stack_in.size() > 0)
            {
                m_stack_out.push(m_stack_in.top());

                m_stack_in.pop();
            }
        }
    }
};

int main()
{
    StackToQueue<int> sq;

    for (int i=0; i<5; ++i)
    {
        sq.add(i);
    }

    while (sq.length() > 0)
    {
        cout << sq.front() << endl;
        sq.remove();
    }

    return 0;
}

输出:

0
1
2
3
4

队列实现栈

问题分析

本质为,用队列 "先进先出"的特性实现栈 "后进先出" 的特性!

解决方案设计

image.png

实现思路

准备两个队列用于实现栈:queue_1[in] 和 queue_2[out]

  • 当有新元素入栈时:将其加入队列[in]
  • 当需要出栈时:

    • 将队列[in]中的 n-1 个元素出队列,并进入队列[out]中
    • 将队列[int]中的最后一个元素出队列(出栈)
    • 交换两个队列的角色: queue_1[out] 和 queue_2[int]

编程实验:用队列实现栈

文件:QueueToStack.h

#include <iostream>
#include "LinkQueue.h"
#include "Stack.h"

using namespace std;
using namespace DTLib;

template <typename T>
class QueueToStack : public  Stack<T>
{
public:
    QueueToStack()  // O(1)
    {
        m_pIn = &m_queue_1;
        m_pOut = &m_queue_2;
    }

    void push(const T &e) override  // O(1)
    {
        m_pIn->add(e);
    }

    void pop() override  // O(n)
    {
        if (m_pIn->length() > 0)
        {
            move();

            m_pIn->remove();

            swap();
        }
        else
        {
            THROW_EXCEPTION(InvalidOpertionExcetion, "No element in current QueueToStack ...");
        }
    }

    T top() const override  // O(n)
    {
        if (m_pIn->length() > 0)
        {
            move();

            return m_pIn->front();
        }
        else
        {
            THROW_EXCEPTION(InvalidOpertionExcetion, "No element in current QueueToStack ...");
        }
    }

    void clear() override  // O(n)
    {
        m_queue_1.clear();
        m_queue_2.clear();
    }

    int size() const override  // O(1)
    {
        return m_queue_1.length() + m_queue_2.length();
    }

protected:
    LinkQueue<T> m_queue_1;
    LinkQueue<T> m_queue_2;
    LinkQueue<T> *m_pIn;
    LinkQueue<T> *m_pOut;

    void move() const  // O(n)
    {
        int n = m_pIn->length() - 1;

        for (int i=0; i<n; ++i)
        {
            m_pOut->add(m_pIn->front());
            m_pIn->remove();
        }
    }

    void swap()  // O(1)
    {
        LinkQueue<T> *temp = nullptr;

        temp = m_pIn;
        m_pIn = m_pOut;
        m_pOut = temp;
    }
};

int main()
{
    QueueToStack<int> qs;

    for (int i=0; i<5; ++i)
    {
        qs.push(i);
    }

    while (qs.size() > 0)
    {
        cout << qs.top() << endl;
        qs.pop();
    }

    return 0;
}

文件:main.cpp

4
3
2
1
0

小结

  • 栈和队列在实现上非常相似,可以相互转化实现
  • 两个栈 "先进后出" 相互配合得到 "先进先出" 的特性
  • 两个对垒 "先进先出" 相互配合得到 "后进先出" 的特性
  • 栈和队列相互转化的学习有助于强化本质的理解

以上内容整理于狄泰软件学院系列课程,请大家保护原创!


TianSong
734 声望138 粉丝

阿里山神木的种子在3000年前已经埋下,今天不过是看到当年注定的结果,为了未来的自己,今天就埋下一颗好种子吧