用栈实现队列,用队列实现栈。好玩!!!

因为在数据结构中,栈和队列长得实在是太像了,将他们拿来比较是不可避免的,栈—后进先出,而队列—先进先出。同样是只能在一端进行操作,那么问题来了,能相互实现??
能不能得好好分析一下嘛,如果是用两个栈来实现队列,好像这操作可以哦。图解一下,你就明白!

在这里插入图片描述
显然用两个栈可以实现队列的功能,就是借助另一个栈来中转一下,这样的操作在图论算法中的dijkstra求最短路径中也会用到。把后进先出转换成先进先出。那么怎么用代码来实现呢?既然需要两个栈,那就定义两个栈呗,一个用于进队列操作,另一个栈就用于出队列操作,完美解决!具体所用的栈和队列在之前的文章已经实现,拿来用就是了。当然用链式的栈和队列是最好的。

实现的时候注意一下细节哦。话不多说,上代码:

#include "LinkStack.h"

template <typename T>
class StackToQueue
{
protected:
	mutable LinkStack<T> in_stack;	// 考虑const对象
	mutable LinkStack<T> out_stack;
public:
	void enqueue(const T& obj)
	{
		in_stack.push(obj);	// 入队压栈就是了
	}
	
	void dequeue()	// 出队需要注意细节的问题
	{
		if( out_stack.size() == 0 )	// 如果出队的栈为空
		{				// 那么就将入队列的栈中元素转移到出队列的栈
			while( in_stack.size() > 0 )
			{
				out_stack.push(in_stack.top());
				in_stack.pop();
			}
			
			out_stack.pop();	// 真正的出队列操作
		}
		else
		{
			out_stack.pop();	//如果出队列的栈有元素,直接出队列
		}
	}

	T front() const		// 获取队头元素的操作与出队操作基本一致
	{
		T ret;
		
		if( out_stack.size() == 0 )	// 如果出队列的栈为空栈
		{				
			while( in_stack.size() > 0 )	// 那么将入队列的栈中元素转移到出队列的栈
			{
				out_stack.push(in_stack.top());
				in_stack.pop();
			}
			
			ret = out_stack.top();	// 栈顶元素就是队头元素
		}
		else				// 这是出队列的栈不为空的情形
		{
			ret = out_stack.top();
		}
		
		return ret;
	}
	
	int length() const	// 直接将两个栈的大小相加再返回
	{
		return out_stack.size() + in_stack();
	}
	
	void clear()	// 将两个栈清空
	{
		out_stack.clear();
		in_stack.clear();
	}
	
	~StackToQueue()
	{
		clear();
	}
};

来,测试一下是否实现了队列的先进先出,把上面实现的代码全部拷贝下面 这个测试程序,我就省略这一步了哈:

#include <iostream>

int main(int argc, const char* argv[])
{
	StackToQueue<int> queue;
	
	for(int i = 0; i < 10; ++ i)
	{
		queue.enqueue(i);
	}
	
	for(int i = 0; i < 10; ++ i)
	{
		cout << queue.front() << " ";
		queue.dequeue();
	}
	
	return 0;
}

在这里插入图片描述
好了,栈实现了队列。那队列怎么实现栈呢,还是看图吧!

在这里插入图片描述

具体用栗子来说明哈。比如上图,一个队列有四个元素,另一个队列则为空,入栈就直接将数据放到用作入栈的队列。

那出栈怎么操作呢,再来看一张图:

在这里插入图片描述

把第一个队列的n-1个元素转移到另一个队列,然后是不是发现第一个队列只剩下一个元素了!是的呢,那么这个元素的位置就相当于栈顶,出栈就很容易了嘛,对第一个队列进行出队列操作就完成啦。获取栈顶元素也一样,不过是出队列的操作换成了获取队头元素,然后将其返回。但是出栈操作之后一定要将入栈的队列和出栈的队列交换,这是用队列实现栈的关键点。

好了,该上代码了:

#include "LinkQueue.h"

template <typename T>
class QueueToStack
{
protected:
	mutable LinkQueue<T> queue1;
	mutable LinkQueue<T> queue2;
	mutable LinkQueue<T>* p_in;	// 用指针来实现交换
	mutable LinkQueue<T>* p_out;	// 效率更高
public:
	QueueToStack()			// 初始化指针
	{
		p_in = &queue1;
		p_out = &queue2;
	}
	
	void push(const T& obj)		// 入栈操作
	{
		p_in->enqueue(obj);	// 直接入队列
	}
	
	void pop()			// 出栈操作,需要注意
	{
		if( p_in->length() >= 1 )	// 如果入队列中有元素
		{
			while( p_in->length() > 1 )	// 那就将n-1个元素转移到出队列
			{
				p_out->enqueue(p_in->front());
				p_in->dequeue();
			}
			
			p_in->dequeue();	// 转移完后对入队列进行出队操作,相当于出栈
			
			LinkQueue<T>* tem = p_in;	// 出栈后就马上交换两个指针的指向
			p_in = p_out;
			p_out = tem;
		}		
		else
		{
			throw(0);
		}
	}
	
	T top() const		// 获取栈顶元素
	{
		T ret;
		
		if( p_in->length() >= 1 )	// 与出栈操作几乎一致,但不需要交换指针的指向
		{
			while( p_in->length() > 1 )
			{
				p_out->enqueue(p_in->front());
				p_in->dequeue();
			}
			
			ret = p_in->front();
		}									
		else
		{
			throw(0);
		}
		
		return ret;
	}
	
	int size() const
	{
		return p_in->length() + p_out->length();
	}
	
	void clear()
	{
		p_in->clear();
		p_out->clear();
	}
	
	~QueueToStack()
	{
		clear();
	}
};


测试一下,是否满足栈的后进先出!

#include <iostream>

using namespace std;

int main(int argc, const char* argv[])
{
	QueueToStack<int> stack;

	for(int i = 0; i < 10; ++ i)
	{
		stack.push(i);
	}
	
	for(int i = 0; i < 10; ++ i)
	{
		cout << stack.top() << " ";
		stack.pop();
	}
	
	return 0;
}

看看输出结果,满足了!
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Dream136/article/details/106850621