一、stack模拟实现
有了vector和list的基础,stack这里我们就不过多的讲解了。stack其本质上就是一个“栈”。数据遵循先进先出的原则。在学习数据结构的时候,想必大家都应该对stack的特点和实现方式有了一定的了解。
在stl的stack的模拟实现之前,我们要先了解“设计模式”。
设计模式并不是我们此次学习的重点,但我们还是要有一定的了解。简单来讲,设计模式就是我们在写代码时所遵循的一些固定的方法。就好比在古代的战争中,许多能人志士根据过去的战役中使用的战术,将其总结起来,写成了“兵法”。后面的人在遇到类似的情况时就可以参考兵法进行排兵布阵。而“设计模式”,就是编程里面的“兵法”。以前的那些计算机大佬对过去的程序员所写出的优秀代码进行总结,研究出了一些在特定情况下比较好用的代码编写方法,就是设计模式。
设计模式现在大概有23种左右,我们现在不必全部了解。在过去,我们其实就已经接触过一种设计模式了,那就是“迭代器”。而现在,我们还要学习一种设计模式,即“适配器模式”。
“适配器模式”大家可能不太理解。举个例子,在我们的日常生活中,存在着大量电源接口。在国内,我们的电压一般都是220V。但是,在国外,他们的电压可能就和我们不同,如英国的电压就是230V。这就会导致我们国内的一些电子产品因为电压不适配无法使用。因此,国内出国时,一般都需要带一个变压器或转换插头,通过变压器或转换插头以适配当地的电压。编程中的“适配器”就和变压器的作用类似,用于将“已有的东西封装转换成你想要的东西”
在学习数据结构时,我们说过,因为stack“先进后出”只需要尾插尾删的特性,选用数组作为其底层结构比较好。因此,我们以前写stack,就会需要去写一个结构体加上几个成员变量,然后用数组去存储。
但是现在我们了解了“适配器模式”后,就可以不再这样写。而是将“vector”作为适配器:
我们查阅库中的stack实现,可以看到,它的构造中有两个参数,第一个传的是类型。而第二个传的就是一个“适配器”,其缺省值为deque。deque是一个“双端队列”,也是一个数据结构,这里先不过多讲解。有了适配器,我们要实现一个栈就很简单了。
#pragma once
#include<iostream>
#include<vector>
#include<list>
using namespace std;
namespace MyStack
{
template <class T, class Container = vector<T>>
class stack
{
public:
void push(const T& x)//数据插入
{
_con.push_back(x);
}
void pop()//数据删除
{
_con.pop_back();
}
const T& top()//获取栈顶元素
{
return _con.back();
}
size_t size()//获取元素个数
{
return _con.size();
}
bool empty()//判断是否为空
{
return _con.empty();
}
private:
Container _con;
};
}
在上面的代码中,就模拟实现好了一个stack。在这里面,我们在类模板中新加入了一个参数“class Container”。该参数用于标志我们所用的适配器。在适配器中,我们默认传入vector。在以前,我们要写一个stack需要多个成员变量,如size、capacity、data等。但是用了适配器后,我们只需要一个Container _con即可。这是一个自定义类型的成员,因此我们甚至不需要写它的构造函数,因为对于自定义类型,编译器会自动调用它的构造函数,这里我们默认传入vector后,创建对象时_con成员变量就会去调用库中的默认构造函数进行构造。
我们再写点代码进行测试:
虽然我们默认传的适配器是vector,但我们也可以手动传入list来实现stack:
同样可以正常运行。
二、queue的模拟实现
queue,简单来讲,其实就是一个“先进先出”的队列。它的概念学过数据结构的应该都很清楚。