目录
在我们用C++模拟实现之前在C语言阶段的实现过的数据结构时,我们会想用更加舒服的方式写代码,这时我们就要用到设计模式
那么我们就要先了解一下什么是设计模式?
一.设计模式
设计模式是前辈们对代码开发经验的总结,是解决特定问题的一系列套路
比如适配器模式,迭代器模式
**迭代器模式:**迭代器封装后提供统一的访问方式,不暴露底层的细节,迭代器实际上是一种设计模式
**适配器模式:**适配器实际上是一种转换,通过已有的东西封装转换出你想要的东西
而我们今天要模拟实现的栈与队列就可以通过适配器模式进行实现
二.stack的模拟实现
关于栈的实现很简单,直接看代码,可以结合代码里标着的注释进行理解~
stack.h
#include<vector>
#include<list>
#include <deque>
namespace wyh
{
	//适配器           //传一个容器  这里用list
	template<class T, class Container = list<T>>
	class stack
	{
	public:
		void push(const T& x)//入栈
		{
			_con.push_back(x);
		}
		void pop()//出栈
		{
			_con.pop_back();
		}
		const T& top()
		{
			return _con.back();
		}
		bool empty()
		{
			return _con.empty();
		}
		size_t size()
		{
			_con.size();
		}
	private:
		Container _con;
	};
}然后我们可以在test.cpp中测试一下:

三.queue的模拟实现
queue.h
namespace wyh
{
	//适配器              //传一个容器  这里用list 
	template<class T, class Container = list<T>>
	class queue
	{
	public:
		void push(const T& x)//入队
		{
			_con.push_back(x);
		}
		void pop()//出队
		{
			_con.pop_front();
		}
		const T& front()//取队头元素
		{
			return _con.front();
		}
		const T& back()//取队尾元素
		{
			return _con.back();
		}
		bool empty()
		{
			return _con.empty();
		}
		size_t size()
		{
			_con.size();
		}
	private:
		Container _con;
	};
}接下来我们对自己写的队列测试一下:

四.deque的简单介绍(了解)
上面我们用list实现了栈和队列,但是当我们查看文档时,发现Container用的并不是
vector或是list,而是deque
那么这个deque又是什么呢?
deque(双端队列):是一种双开口的"连续"空间的数据结构
双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1)
它与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高
deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,由buffer数组构成,确定中控指针数组:

与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率是必vector高的
与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段
所以说,deque集成了vector和list的优点,它的出现本来是想取代vector和list,但是,正如大家所见,它并没有成功,否则我们学习的第一个容器也不会是vector或者list了
那么deque的缺陷又是什么呢?
deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑vector和list,deque的应用并不多
而目前能看到的一个应用就是,STL用其作为stack和queue的底层数据结构
最后一个问题:
为什么选择deque作为stack和queue的底层默认容器?
- 
stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端操作 
- 
在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的元素增长时,deque不仅效率高,而且内存使用率高 
五.课后习题
155.最小栈
参考代码:
class MinStack //因为这个函数 所以采用2个栈的实现方式
{
public:
    stack <int> s1;
    stack <int> s2;
    MinStack() 
    {}
    
    void push(int val) 
    {
       s1.push(val);
       if (s2.empty() || s1.top() <= s2.top()) //s2为空或者val值比s2中更小
            s2.push(s1.top());
    }
    
    void pop() 
    {
        if (s1.top() == s2.top()) //s1出栈元素与s2顶部相同
            s2.pop();
        
         s1.pop();
    }
    
    int top() 
    {
       return s1.top();
    }
    
    int getMin() 
    {
       return s2.top();
    }
};栈的压入、弹出序列
参考代码
class Solution 
{
public:
    bool IsPopOrder(vector<int>& pushV, vector<int>& popV) 
    {
        stack <int> s;
        int pushi = 0;//作为操控pushV这个压入栈的指针
        int popi = 0; //作为操控popV这个弹出栈的指针
        
        for(pushi = 0;pushi<pushV.size();pushi++)
        {
            //1.入一个pushV中的值
            s.push(pushV[pushi]);
            //2.s 跟popV 比较
            while(!s.empty() && s.top() == popV[popi])
            {
            //相等 出栈序列popV往后走 s的栈顶元素出
            ++popi;
            s.pop();
            }
            
            //不相等 出来 进行下一次循环
        }
        
        //s不为空,为false
        if (!s.empty()) return false;
        //s.empty()即s这个栈的所有数都出栈了,则为true
        else   return true;
    }
};232.用栈实现队列
参考代码:
class MyQueue 
{
public:
   stack <int> s1;//用来返回队列的值
   stack <int> s2;
    MyQueue() //构造 不用写了
    {}
    
    void push(int x)  //push 是关键
    {
        while(!s1.empty())//x进来之前,先把s1的数全挪到s2去
        {
            s2.push(s1.top());
            s1.pop();
        }
      
        s1.push(x);//x入栈
       // 将s2中放着的s1的数全挪回来 如此可以保证用栈保持s1是队列的顺序
        while(!s2.empty())
        {
            s1.push(s2.top());
            s2.pop();
        }
    }
    
    int pop() //出队列 并返回这个出队的元素
    {
        int x = s1.top();
        s1.pop();
        return x;
    }
    
    int peek() ///返回对列的顶部元素
    {
      return s1.top();
    }
    
    bool empty() //判断队列是否为空
    {
     return s1.empty();
    }
};225.用队列实现栈
参考代码:
class MyStack 
{
public:
    queue<int>q1;//返回值在q1实现
    queue<int>q2;
    MyStack() 
    {}
    
    void push(int x) 
    {
       q1.push(x);
    }
    
    int pop() //关键  使得我们用队列的结构模拟出栈的序列
    {
      //思路 : 出q1队列的元素到q2使得它只剩一个元素,再将这最后一个元素弹出
             // 当然了 当q1的元素弹出后 我们还要将q2的元素还原回q1
        
         int ans=q1.back();
        int n=q1.size()-1;
        while(n--)//出q1队列的元素到q2使得它只剩一个元素,再将这最后一个元素弹出就是我们要的
        {
            q2.push(q1.front());
            q1.pop();
        }
       
        q1.pop();
        //q1的元素弹出后 将q2的元素还原回q1
        while(!q2.empty())
        {
            q1.push(q2.front());
            q2.pop();
        }
        return ans;
    }
    
    int top() 
    {
     return q1.back();
    }
    
    bool empty() 
    {
        return q1.empty();
    }
};
