C++stack与queue模拟实现

C++stack与queue模拟实现

前言

xxxx无论是当初在学校最先学习C语言版的数据结构,还是现在学习STL,发现大家(包括我)都喜欢将stack(栈)和queue(队列)放在一起。可能是FILO和FIFO两种数据存储方式过于相近,更能深入人心,因此两者经常会被放在一起。但是STL我把他们放在一起更是有原因。因为这两种容器在模拟实现的时候,都会使用到“适配器”。这个在后面我再具体说明。

stack栈

xxxx栈的基本知识相信大家都已经了解,在此我就不再赘述。栈的逻辑结构如图
C++stack与queue模拟实现
现在我们就要用C++进行实现。我们当初用C语言实现栈的时候,最多的情况都是使用的数组来模拟栈。数组的头代表数组的栈底;数组的尾代表栈顶。由于栈对数据的push、pop都是在栈顶操作,所以使用数组就能在时间复杂度为O(1)的情况下完成操作,十分高效。
xxxx这里有一个很重要的事情,就是C语言中,我们用数组来模拟栈。那C++呢??数组的结构特点非常适合来作为栈,所以我们能否仍然使用数组(vector)来作为栈的基础数据结构从而实现栈呢?
xxxx答案是肯定的,我们仍然需要使用数组(不是说只能使用数组,只不过数组更普遍,并且STL中的stack就是使用vector来实现的)但是我们知道,栈还有链栈,或者某些特殊要求我们不能使用vector,而是其他的容器更适合当前的操作情况。这时候,为了代码的通用性,避免代码冗余,为了面对不同的需要,我们不用每次都要写一份逻辑相同而使用的容器不同的stack,我们就要引入**“适配器”**的概念。

适配器

提前声明:我在这里讲的适配器,只是适配器的一小部分,对于模拟实现stack和queue所需要的部分。
xxxx什么是适配器?大家现实生活中应该都有许多类型的适配器。比如:家用220V电压是从高压输电线通过电压转变过来的、两孔三孔插头之间转化……功能类似于下图这种。
C++stack与queue模拟实现
xxxx简单来说,就是一种转变。而在这里是什么的转变呢?答案是:容器的转变。
xxxx现在我们的目的是使用各种转变成stack。我们就需要模板。类模板详解请点这里。下面我们直接看一下如何使用模板成为适配器。

template<class T, class Container = vector<T>>	
class stack
{
private:
	Container _con;
};

以上就是它的基本格式。我们最简单的理解就是,我们将vector进行一次封装。通过成员函数对他的行为进行约束,让他变成具有stack属性的一种新容器,这种容器我们成为stack。
C++stack与queue模拟实现
注:STL中使用的是deque,我们使用vector影响不大,使用vector与C语言有很好的联系,方便理解,否则有些同学刚学到这里,还不知道deque是什么,会影响学习

stack的成员函数

namespace zzk
{
	template<class T, class Container = std::deque<T>>
	class stack
	{
	public:
		//默认成员函数都不用写,就直接使用deque的就行
		void push(const T x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_back();
		}
		T top() const
		{
			return _con.back();
		}
		size_t size() const
		{
			return _con.size();
		}
		bool empty() const
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}

xxxx我们可以很容易发现,完全就是对vector成员函数进行一次封装,因为操作逻辑完全一样,所以只需要对vector的行为封装成stack即可完成。

queue队列

xxxx我们在C语言中的队列可以用链表或者数组。
C++stack与queue模拟实现

在C++中,我们仍然要使用适配器这种方式,对某种容器进行封装,形成队列。由于vector不支持头删,所以我们要使用deque或者链表。STL中默认使用的是deque。
C++stack与queue模拟实现
经过stack的学习,queue应该比较容易理解,我们直接上代码!!

queue类

namespace zzk
{
	template<class T, class Container = std::deque<int>>
	class queue
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_front();
		}
		T front()
		{
			return _con.front();
		}
		bool empty()
		{
			return _con.empty();
		}
		size_t size()
		{
			return _con.size();
		}
	private:
		Container _con;
	};
}

xxxx还是对已有容器的封装,由于逻辑类似,因此我们直接复用原容器的接口即可。

总结

xxxx栈和队列都使用了“适配器”,在这里,适配器的作用就是对现有容器的一种封装,由于操作逻辑相同,因此只需要对接口进行一次封装即可。对于逻辑不相同的。如用vector实现优先队列priority_queue,由于逻辑不相同,就需要加以其他代码,使符合priority_queue的功能特点。

上一篇:JDBC-SQLserver


下一篇:通讯录(c语言版本)