一:题目
用两个栈实现一个队列。完成在队列尾部插入结点和在队列头部删除结点的功能。
二:题目分析
首先,让我们知道队列是“先进先出”的特性,而栈是“先进后出”的特性。那么使用两个栈实现一个队列的功能。我们可以想到的是一个栈用于作为入队列的容器,另一个栈可以用来作为出队列的容器。
根据栈的“先进后出”的特性,栈二中的内容可以存放栈一的栈顶元素。然后栈二的栈顶元素就是入队的第一个元素。那么就会有如下的操作步骤:
- 入队列操作即就是入栈一的操作;
- 出队列时,先判断栈二中是否有元素,有元素则出栈,否则将栈一的元素压入栈二中,然后再通过栈二进行出栈操作。
三:源码
根据以上,在不考虑线程安全的情况下,不难写入如下的代码:
#include <stack>
template<typename T>
class EQueueFromVector {
public:
EQueueFromVector();
~EQueueFromVector();
void Push(const T& item);
T Pop();
private:
std::stack<T> m_stackPush;
std::stack<T> m_stackPop;
};
template<typename T>
EQueueFromVector<T>::~EQueueFromVector() {
}
template<typename T>
EQueueFromVector<T>::EQueueFromVector() {
}
template<typename T>
void EQueueFromVector<T>::Push(const T& item) {
m_stackPush.push(item);
}
template<typename T>
T EQueueFromVector<T>::Pop() {
T item;
if (m_stackPop.size() > 0) {
item = m_stackPop.top();
m_stackPop.pop();
return item;
}
int nSize = m_stackPush.size();
if (nSize <= 0) {
return item;
}
for (int i = 0; i < nSize; i++) {
m_stackPop.push(m_stackPush.top());
m_stackPush.pop();
}
item = m_stackPop.top();
m_stackPop.pop();
return item;
}
三:测试
printf("push num: ");
EQueueFromVector<int> queue;
for (int i = 0; i < 5; i++) {
queue.Push(i);
printf("%d,\t", i);
}
printf("\npop num: ");
for (int j = 0; j < 5; j++) {
int n = queue.Pop();
printf("%d,\t", n);
}
printf("\n");
根据测试代码得到以下结果:
三:扩展
上面是通过两个栈实现一个队列,那么如何使用两个队列实现一个栈呢。
实际上对于入栈的操作相对来说简单的,入栈即是入队列。那么出栈呢,为了保证出栈满足“先进后出”的原则。我们假设:a、b、c已经入队列1,那么这时第一个出栈的应该是c。如何能够让c出栈呢。办法只有一个,先将a、b取出来,c才能从队列中出来。那么,我们的a、b就只能先出队列1然后保存到队列2中。最后队列1中就只剩下c,即可做出栈操作。
根据以上规律,不难看出,这两个队列就像两个簸箕一样,来回倒就把最低下的元素倒出来了。即接上,如果再次出栈,就可以把队列2的a元素先放入队列1中,然后再将b元素出栈。这个时候如果再有d元素入栈,则直接入不为空的队列即可。
通过以上的分析不难写出如下的代码:
template<typename T>
class EVectorFromQueue {
public:
EVectorFromQueue();
~EVectorFromQueue();
void Push(const T& item);
T Pop();
private:
std::queue<T> m_queue[2];
int m_nCurPushIndex;
};
template<typename T>
EVectorFromQueue<T>::EVectorFromQueue()
: m_nCurPushIndex(0){
}
template<typename T>
EVectorFromQueue<T>::~EVectorFromQueue() {
}
template<typename T>
void EVectorFromQueue<T>::Push(const T& item) {
m_queue[m_nCurPushIndex].push(item);
}
template<typename T>
T EVectorFromQueue<T>::Pop() {
if (m_queue[0].empty() && m_queue[1].empty()) {
throw std::exception("stack is empty");
}
if (m_queue[m_nCurPushIndex].empty() || !m_queue[!m_nCurPushIndex].empty()) {
throw std::exception("stack is exception");
}
int nPopIndex = m_nCurPushIndex;
m_nCurPushIndex = (m_nCurPushIndex + 1) % 2;
while (m_queue[nPopIndex].size() > 1) {
m_queue[m_nCurPushIndex].push(m_queue[nPopIndex].front());
m_queue[nPopIndex].pop();
}
T item = m_queue[nPopIndex].front();
m_queue[nPopIndex].pop();
return item;
}
测试代码如下:
printf("push num: ");
EVectorFromQueue<int> stack;
for (int i = 0; i < 5; i++) {
stack.Push(i);
printf("%d,\t", i);
}
printf("\npop num: ");
for (int j = 0; j < 3; j++) {
int n = stack.Pop();
printf("%d,\t", n);
}
printf("\npush num: 6, 7");
stack.Push(6);
stack.Push(7);
printf("\npop num: ");
for (int i = 0; i < 4; i++) {
int n = stack.Pop();
printf("%d,\t", n);
}
printf("\n");
测试结果如下: