剑指Offer之用两个栈实现队列

一:题目

  用两个栈实现一个队列。完成在队列尾部插入结点和在队列头部删除结点的功能。

二:题目分析

  首先,让我们知道队列是“先进先出”的特性,而栈是“先进后出”的特性。那么使用两个栈实现一个队列的功能。我们可以想到的是一个栈用于作为入队列的容器,另一个栈可以用来作为出队列的容器。
  根据栈的“先进后出”的特性,栈二中的内容可以存放栈一的栈顶元素。然后栈二的栈顶元素就是入队的第一个元素。那么就会有如下的操作步骤:

  1. 入队列操作即就是入栈一的操作;
  2. 出队列时,先判断栈二中是否有元素,有元素则出栈,否则将栈一的元素压入栈二中,然后再通过栈二进行出栈操作。

三:源码

  根据以上,在不考虑线程安全的情况下,不难写入如下的代码:

#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");

  测试结果如下:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

非正经程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值