0
点赞
收藏
分享

微信扫一扫

STL之Stack与queue的模拟实现与duque的底层结构(3千字长文详解)

STL之Stack与queue的模拟实现与duque的底层结构

设计模式的概念

设计模式像是古代的兵法,是以前的人总结出来的一些在特定的情况下,某种特定的好用的方法总结

STL中迭代器也是一种设计模式——==迭代器模式==

STL中stack和queue的实现就是使用了一种设计模式——==适配器模式!==

适配器模式

那么什么叫做适配器模式呢?现实中什么东西可以被叫做适配器?

例如手机充电头!——就是一种电源适配器!我们日常的电源一般都是220v,但是手机一般的充电功率都是几v!如果不使用电源适配器,那么直接充电很容易会让手机坏掉!

==所以适配器模式是什么?适配器模式就是一种转换!用已有的东西转换出我们现在想要的东西!==

stack的实现

#include <vector>
#include <list>
namespace MySTL
{
	template<class T, class Container = std::vector<T>>
	class stack
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_back();
		}
		bool empty()
		{
			return _con.empty();
		}
		const T& top()
		{
			return _con.back();
		}
		size_t size()
		{
			return _con.size();
		}

	private:
		Container _con;
	};
}
//test.cpp
//测试代码
int main()
{
	MySTL::stack<int, vector<int>> s1;
	//MySTL::stack<int, list<int>> s1;
	s1.push(1);
	s1.push(2);
	s1.push(3);
	s1.push(4);
	s1.push(5);

	while (!s1.empty())
	{
		cout << s1.top() << " ";
		s1.pop();
	}
	cout << endl;
	return 0;
}

==Container 这个模板参数的意义就在于能够让我们哦stack更加的灵活!因为无论是vector实现的栈和list实现的栈都有各自的优点!都难以互相代替!既然如此就将其写成一个模板参数!需要的时候就替换!==

==我们可以给这个模板参数一个缺省值默认是vector<T>,想要的适合再进行替换!==

queue的实现

#include<list>
#include<vector>
namespace MySTL
{
	template<class T,class Container = std::list<T>>
	class queue
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);//尾插
		}
		void pop()
		{
			_con.pop_front();//头删
		}
		bool empty()
		{
			return _con.empty();
		}
		const T& front()//获取头元素
		{
			return _con.front();
		}
		const T& back()//获取尾元素
		{
			return _con.back();
		}
		size_t size()
		{
			return _con.size();
		}	
	private:
		Container _con;
	};
}

//test.cpp
#include "queue.h"
int main()
{
	MySTL::queue<int> s1;
	//MySTL::queue<int,list<int>> s1;
    //MySTL::queue<int,vector<int>> s1;
	s1.push(1);
	s1.push(2);
	s1.push(3);
	s1.push(4);
	s1.push(5);

	while (!s1.empty())
	{
		cout << s1.front() << " ";
		s1.pop();
	}
	cout << endl;
	return 0;
}

 MySTL::queue<int,vector<int>> s1;

这个使用vector的时候,使用pop的会报错!因为vector是不支持pop_front!

==也不提倡使用vector作为队列的底层!因为这样子头删的效率会很低!是O(N)==

==stack和queue虽然说是容器!但是准确的说是容器适配器!==——是用容器适配转换出来的!

双端队列——deque

image-20230403111808796

我们可以看到库里面的stack和queue全部的默认容器其实不是list和vector!==而是deque==——这是双端队列!

为什么是用deque这个容器呢?——这就不得不提到vector和list的缺点了!

deque的底层结构

==这里我们简单的介绍一下deque的底层结构!==

deque是由==多个buff数组构成的==!——而由一个==中控数组(指针数组)==来管理所有的buff数组

image-20230403165219806

等一个buff数组满了之后,如果对于一般的vector,就应该开始扩容,==但是对于deque,不会进行扩容,而是开第二个buff数组==

image-20230403165956827

==第二个buff满了就开下一个,直到中控数组的也满了之后!才需要对中控数组进行扩容!==

==上面的插入操作都是尾插!==

如果要进行头插呢?——是要挪动位置吗?不是!==而是也是新开一个数组!==

==头插插入那个buff数组最右边开始!==

==这样子设计,它的CPU缓冲区命中率也可以,头插效率也不错!==——虽然看上去也会有空间浪费!但是其实buff数组一般都比较小,相比vector一次性二倍扩或者1.5倍扩,造成的浪费是可以接受的!

==那么这个deque的随机访问是如何实现的?==

image-20230403172151456

举报

相关推荐

0 条评论