文章目录
前言
本篇对stl库中stack和queue进行模拟实现,我们当前实现的目的并不是创造比库中更好的容器,而是旨在加深我们对库的理解,加强我们代码实现能力,以及锻炼我们的代码编写能力。
stack模拟
一、模拟前准备
知其然
模拟之前需要 先知道栈和队列的基本原理,均是初阶数据结构的知识,如果对此不熟悉,请移步文章:
链接1: 【数据结构】第四站:栈(附源码)
链接2: 【数据结构】第五站:队列(附源码)
看源码
模拟前还是先看库中源码:
①看成员变量
发现看不懂,这个_Sequence是什么呢?
stack的模版参数列表可知,_Sequence是stack的一个模版参数,它接收一个传入的类型,并且可以在模版内部使用该类型。
这里它给了_Sequence一个默认的参数,这个deque是什么呢?
查看cpp文档可知,
deque是一个库中的容器,并且有它自己的表头。
我们这里便是将deque传入我们的模版stack中,套用了deque中的许多成员函数,从而完成我们对stack的实现,这种对其他容器的套用(将一个容器适配成另一个容器)模式,正如我们的电源适配器(手机充电头)一样。不过充电头是将电压适配成合适的电压,而我们这里是将一个容器适配成了另一个合适的容器,这便是我们的 适配器模式 ,这个词和其原理应用在后面还会有涉及,请深刻理解它。
②再找到我们的构造函数
这里stack的构造函数是传入了一个_Sequence变量的引用对我们stack进行初始化的,直接用初始化列表,调用_Sequence这个类(也就是deque类)的拷贝构造,将传入的_Sequence对象的值拷贝给了我们stack内部的_Sequence对象。这里还给了一个缺省值,这个缺省值可以保证如果没有传入_Sequence对象的话便调用_Sequence类的默认构造创造了一个匿名对象并将它传入。
③再找到我们插入函数
从插入函数我们就能更好的理解我们的适配器模式了,我们调用stack::push将传入的数据插入它内部的容器中,我们根据stack的规则对stack内部的容器(模版类型传入的)_Sequence变量(deque容器)进行改动,从外部看就是一个stack。
二、模拟实现代码
大致实现代码,旨在理解我们库中设计模式,加深对库的理解。
#include<deque>
template<class T, class Con = deque<T>> //我们包含deque容器的头文件,用deque作为stack内部实现的容器
class stack //stack模版
{
public:
stack() //stack的构造函数,什么都不用加,因为其实我们传入的Con = deque<T>是一个类型,我们用该类型创建的成员变量是一个自定义类型,而类中的自定义类型是会自动在类的初始化列表调用其自定义类型的默认构造函数的,这里和我们的库中并无不同,只是我们就无法自己传入_Sequence对象为stack成员变量的_Sequence对象初始化了。
{}
void push(const T& x) //对stack的插入即是对我们的deque<T>变量_c插入,且这是一个stack,需要保证单边进出,且前进后出。
{
_c.push_back(x);
}
void pop()
{
_c.pop_back();
}
T& top()
{
return _c.back();
}
const T& top()const
{
return _c.back();
}
size_t size()const
{
return _c.size();
}
bool empty()const
{
return _c.empty();
}
private:
Con _c;
};
queue模拟
我们queue的实现基本和stack一样,也是使用适配器模式实现的,用deque做内部容器,实现了外部queue容器。
一、模拟前准备
看源码
①成员变量
②构造函数
③插入/删除函数
这里开始就和我们的stack不同了,虽然它们都是使用了适配器模式并使用deque实现的,但是,我们对不同容器的规则是不一样的,stack是单口先进后出,而queue是单口先进后出,这里两个容器的规则有本质的区别,但是我们却使用同一个容器去实现,可以吗?可以的,deque同时具有了链表和顺序表的部分特性,它可以实现头插也可以实现尾插,它们均效率不错,详细可以移步搜索本人另篇文章。如果我们没有这样一个容器deque,那么我们对stack构造的缺省和queue构造的缺省就要分别给vector容器和list容器,这样也可以,但是同时也各自具备了它们的缺点,虽然我们的deque也不是完美,它也只是有自己的特点(头插头删/尾插尾删)效率不错。
这里queue的push是对内部容器c的尾部插入。
而这里的queue删除却是对c的头部删除,以完成对队列的规则约束:只能尾插头删。
二、模拟代码实现
template<class T, class Con = deque<T>>
class queue
{
public:
queue()
{}
void push(const T& x)
{
_c.push_back(x);
}
void pop()
{
_c.pop_front();
}
T& back()
{
return _c.back();
}
const T& back()const
{
return _c.back();
}
T& front()
{
return _c.front();
}
const T& front()const
{
return _c.front();
}
size_t size()const
{
return _c.size();
}
bool empty()const
{
return _c.empty();
}
private:
Con _c;
};
总结
本文对c++、stl库中stack和queue进行简单分析及代码的简单模拟实现,旨在加深理解。
本文章为作者的笔记和心得记录,顺便进行知识分享,有任何错误请评论指点:)。