C++STL详解(六)——stack和queue

空间适配器

适配器是一种设计模式(设计模式是一套被反复使用的,多数人知晓的,经过分类编目的,代码设计经验的总结),该种模式是将一个类的接口转换客户希望的另外一个接口。

虽然stack和queue中也可以存放元素,但在STL中却并没有划分到容器的行列,而是将其称为容器适配器,这是因为stack和队列只是对其他容器的接口进行了包装,当我们没有显示传时,STL中stack和queue默认使用deque。
例如:
如果我们定义一个stack,并指定使用vector容器,则定义出来的实际出来的stack就可以
复用vector的接口来实现栈的各个函数接口。
在这里插入图片描述
在这里插入图片描述

stack

stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其只能从容器的一段继续元素的增删操作。

stack的定义方式

方式一:使用STL中默认的适配器定义栈。(默认为deque)

	stack<int> s1;

方式二:使用特定的适配器定义栈

    stack<int, vector<int>> st2;
	stack<char, vector<char>> st3;

stack的使用

在这里插入图片描述

int main()
{
	stack<int, vector<int>> st1;
	st1.push(1);
	st1.push(2);
	st1.push(3);
	while (!st1.empty())
	{
		cout << st1.top() << endl;
			st1.pop();
	}//3 2 1
	cout << st1.size() << endl;   //0
	return 0;
}

stack的模拟实现

1:为了体现vector适配器特性,在初始栈的基础上增加一个模板参数Container,并用deque默认容器作缺省值。
2: 根据我们所传的容器类型,就变成指定容器类型的适配器,进而复用指定容器的接口实现stack成员函数,进而实现stack的各种功能。

namespace yzh
{
	template <class T,class Container = deque<T>>
	class stack
	{
	public:
		//构造,拷贝构造,赋值都不需要。
		//编译器会调用自定义类型参数。
		void push(const T& x)    //尾插
		{
			_con.push_back(x);            //复用vector的push_back();
		}
		void pop()              //尾删
		{
			_con.pop_back();             //复用vector的pop_back();
		}
		const  T& top() const            //栈顶不可以被修改。
			 return _con.back();         //复用vector的back();
		}
		 size_t size() const 
		 {
			 return _con.size();        //复用vector的size();
		 }
		 bool empty() const
		 { 
			 return _con.empty();        //复用vector的empty;
		 }
		 
	private:
		Container _con;
	};
}

queue

queque是一种容器适配器,专门用具有先进先出的操作的上下文环境中,其只能从容器的一端插入元素,另一端提取元素。

queue的定义方式

定义方式一:使用STL中默认的适配器定义队列。(默认为deque)

queue<int> q1;

定义方式二:使用特定的适配器定义队列。

	queue<int, vector<int>> q2;
	queue<char, list<char>> q3;

queue的使用

在这里插入图片描述
因为queue的接口存在头删和尾插,如果使用vector封装效率太低,所以一般借助lsit来封装。

int main()
{
	queue<int, list<int>> q1;
	q1.push(1);
	q1.push(2);
	q1.push(3);
    cout<<q1.back()<<endl;
	while (!q1.empty())
	{
		cout << q1.front() << endl;
		q1.pop();
	}//3 2 1
	cout << q1.size() << endl;   //0
	return 0;
}

queue的模拟实现

1: queue不能使用vector容器封装,头插尾删效率太低。
2:写两种front和back成员函数是为支持const队列调用const front和const back ,它们的返回值是可读但不可以写的,普通队列调用普通front和普通back,返回值可读可写。

namespace yzh
{
	template<class T, class Container = deque<T>>
	class queue
	{
	void push(const T& x)                //队尾入队列。
		{
			_con.push_back(x);
		}
		void pop()                          //对头出队列。
		{
			_con.pop_front();
		}
		T& front()
		{
			return _con.front();
		}
		//返回值可以被修改
		T& back()
		{
			return _con.back();
		}
		//返回值不可以被修改。
		T& front()
		{
			return _con.top();
		}
		const T& back()const
		{
			return _con.front();
		}
		//不可以被修改。
		const T& front() const
		{
			return _con.front();
		}
		bool empty() const
		{
			return _con.empty();
		}
		size_t size() const
		{
			return _con.size();
		}
}

浅谈deque容器

deque的原理介绍

deque(双端队列): 是一种双开口的"连续"空间的数据结构,就是由一个个小数组buffer拼接而成,实际deque类似于一个动态的二维数组.

优势:
deque容器: 既能在头删和头插,又能支持尾部插入删除,还能随机访问.

vector容器: 底层是一个顺序表,支持随机访问,尾插尾删,但是不支持头插头删.

list容器: 底层是一个链表,支持头插头删,尾插尾删,但是不支持随机访问.

缺陷:
1:不适合遍历,因为在遍历时,deque的迭代器需要频繁的去检测是否移动到末端小数组buffer的边界,以防越界. 进而导致效率低下,而在序列式场景中,可能经常需要遍历,因为在实际中,需要线性结构时,大多情况下优先考虑vector和list.一般在stack和queue的底层数据结构中考虑deque
2: buffer数组中间的插入删除效率不高.
3: 底层角度迭代器实现复杂.

为什么选择deque作为stack和deque的底层默认容器?

stack是一种后进先出的底层线性结构,只要支持尾插尾删都可以作为stack的底层容器,比如:
vector和list, queue是一种先进先出的线性结构,只要支持尾插和头删的操作就可以.比如:list.

原因:
1: stack和queue不需要遍历(因此stack和queue)没有迭代器,只需要在固定的的一端或者两端进行操作.
2:stack元素增长需要扩容时,deque比vector的效率高(扩容时不需要大量搬移数据),并且deque扩容时不像vector一样两倍或者n倍的扩容,而是固定的一个小数组buffer.这样空间利用率较高.

三种迭代器

迭代器分类:

单向迭代器: forword

双向迭代器: bidirectional

随机迭代器: random_access

常见迭代器功能分类:
在这里插入图片描述
例如:
当我们调用sort和reverse时,因为sort的迭代器是随机迭代器,reverse的迭代器是双向迭代器,所以我们必须匹配相应的迭代器.

在这里插入图片描述
注意:
1:随机迭代器算作一种特殊的双向迭代器,双向得带起算作一种特殊的单向迭代器.因为随机迭代器满足双向迭代器的所有功能,双向迭代器满足单向迭代器所有功能.
2: 所以reverse算法,我们既可以使用双向迭代器也可以使用随机迭代器.但是不可以使用单项迭代器,因为双向迭代器的功能单向迭代器并没有.

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暂停更新

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值