c++中容器适配器

本文深入探讨了容器适配器的设计模式,详细介绍了如何通过封装底层容器如deque、vector和list来实现stack、queue和priority_queue等数据结构,强调了容器适配器在满足特定接口需求上的灵活性和实用性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是容器适配器

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

stack模拟封装

template<class T,class Container = deque<T>>
	class stack
	{
	public:
		stack()
		{}

		void push(const T& data)
		{
			_con.push_back(data);
		}

		void pop()
		{
			_con.pop_back();
		}

		size_t size()const
		{
			return _con.size();
		}

		bool empty()const
		{
			return _con.empty();
		}

		T& top()
		{
			return _con.back();
		}

		const T& top()const
		{
			return _con.back();
		}
	private:
		Container _con;
	};

queue模拟封装

template<class T , class Container = deque<T>>
	class queue
	{
	public:
		queue()
		{}

		void push(const T& data)
		{
			_con.push_back(data);
		}

		void pop()
		{
			_con.pop_front();
		}

		T& front()
		{
			return _con.front()
		}

		const T& front()const
		{
			return _con.front()
		}

		T& back()
		{
			return _con.back();
		}

		const T& back()const
		{
			return _con.back()
		}

		size_t size()const
		{
			return _con.size();
		}

		bool empty()const
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
  • 每种容器都提供了一组接口,如果容器中的接口不能满足需求,那么重新编写容器还是改变我们的需求
  • 应该构造一个容器接口到需求接口之间的转换器,称为容器适配器。
  • 容器适配器将原容器进行了一层封装,底层基于普通容器,上层对外提供封装后的新接口,满足不同使用者的需求。常用的栈stack、队列deque、优先级队列priority_queue在STL中都有自己的容器适配器。
  • 容器适配器对使用者是个黑盒,使用者无需知道容器适配器封装的容器类型,而只需了解容器适配器提供的接口。除了使用STL提供的容器适配器,也可以自己构造容器适配器,将STL中的容器进行封装,对外提供所需的接口。
  • 容器适配器可以封装的容器类型根据容器适配器对外提供的接口和容器适配器的内部算法而定。但是任何容器适配器对底层容器都有一些通用的要求,例如,底层容器必须支持添加删除 和访问尾元素操作,因此array不能作为容器适配器的底层容器。
  • 栈适配器和队列适配器默认的底层容器是deque,优先队列适配器默认的底层容器是vector。在创建容器适配器的对象时,也可以指定其他合理的容器作为容器适配器的底层容器。创建容器适配器对象的方式如下
栈:

stack<int> s;//默认使用deque

stack<int,vector<int>> s;//指定使用vector
队列:

queue<int> q;//默认使用deque

queue<int,lise<int>> q;//指定使用list

优先队列:

priority_queue<int> p;//默认使用vector

priority_queue<int,deque<int>> p;//指定使用deque

priority_queue<int,vector<int>,cmp>> p;//指定使用vector和权重比较函数cmp

注意事项
容器适配器和底层容器是组合的关系,插入容器适配器中的元素最终都保存在底层容器中,容器适配器中的数据成员包括一个用于存储元素的底层容器对象和一些辅助数据。

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

stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的线性结构,都可 以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有 push_back和pop_front操作的线性结构,都可以作为queue的底层容器,比如list。但是STL中对stack和 queue默认选择deque作为其底层容器,主要是因为:

  1. stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
  2. 在stack中元素增长时,deque比vector的效率高;queue中的元素增长时,deque不仅效率高,而且内 存使用率高。
<think>好的,我现在需要详细讲解C++中的容器适配器,包括stack、queue和priority_queue。首先,我应该回顾用户提供的引用内容,确保准确引用相关信息。用户已经给出了一些引用资料,其中提到了容器适配器的基本概念、实现方式以及各个适配器的特点。 首先,我需要明确容器适配器的定义。根据引用[1],容器适配器是一种将现有容器转换为特定接口(如栈、队列、优先级队列)的机制。它们不自己管理数据,而是通过封装一个底层容器来提供新的功能。接下来,我需要分别介绍stack、queue和priority_queue,包括它们的特点、常用方法和底层实现。 对于stack,引用[1]提到它是先进后出(FILO)的结构,底层容器需要支持push_back和pop_back,因此可以是vector、deque或list。不过引用[3]指出不能使用vector作为适配器,因为vector不支持头删,但stack只需要尾插和尾删,所以这里可能存在误解。需要确认正确性,可能引用[3]中的描述有误,或者是指queue的情况? 然后是queue,引用[1]和引用[3]提到queue是先进先出(FIFO),需要支持pop_front和push_back,因此底层容器不能是vector(因为vector不支持头删),通常使用deque或list。引用[5]展示了queue的模拟实现,使用deque作为默认容器。 接下来是priority_queue,引用[1]和引用[4]指出它需要支持随机访问,因此底层容器通常是vector或deque。priority_queue通过堆算法实现,元素按优先级顺序出队。引用[4]还提到了初始化时建堆的过程,这涉及到向下调整算法(adjust_down)。 在结构上,应该按照每个容器适配器分点讲解,包括介绍、底层容器、常用接口、实现细节和应用场景。同时需要对比它们之间的区别,例如底层容器的选择原因,时间复杂度等。 需要注意用户之前的提问关于list的详解,现在转向容器适配器,可能需要强调适配器容器的不同,即适配器是包装现有容器提供特定接口。同时,用户可能对如何选择底层容器感兴趣,例如为什么stack默认使用deque,而priority_queue使用vector。 需要确保引用正确的来源,例如在讨论stack的底层容器时,引用[1]指出可以使用支持push_back和pop_back的容器,而引用[3]提到不能使用vector作为适配器,可能是指queue的情况,这里需要澄清,避免混淆。 另外,用户可能关心容器适配器的实现方式,例如如何通过封装底层容器的方法来提供适配器的接口。例如,stack的push方法调用底层容器的push_back,pop调用pop_back等。模拟实现的代码示例可以帮助理解,如引用[3]和[5]中的代码片段。 最后,生成相关问题时要围绕容器适配器的特点、实现、使用场景和比较,例如与直接使用底层容器的区别,如何自定义适配器的底层容器等。</think>### C++ 容器适配器详解:stack、queue、priority_queue #### 一、容器适配器基础概念 容器适配器是**基于现有容器封装**的特殊数据结构,通过限制或扩展接口实现特定功能,不直接管理内存,而是依赖底层容器存储数据[^1][^2]。核心特点: - 提供受限的接口(如栈的先进后出) - 底层容器可指定(需满足特定操作要求) - 包含在`<stack>`、`<queue>`头文件中 $$ \text{适配器} = \text{现有容器} + \text{特定接口限制} $$ --- #### 二、三大容器适配器详解 ##### 1. **stack(栈)** - **特性**:先进后出(FILO),仅允许在栈顶操作 - **底层容器**:需支持`push_back()`、`pop_back()`,默认使用`deque`,也可选`vector`或`list`[^1][^3] - **核心操作**: ```cpp stack<int> s; s.push(10); // 压栈 $O(1)$ s.pop(); // 弹栈 $O(1)$ s.top(); // 查看栈顶 $O(1)$ ``` - **实现原理**: ```cpp template<class T, class Container = deque<T>> class stack { private: Container _c; // 底层容器 public: void push(const T& val) { _c.push_back(val); } void pop() { _c.pop_back(); } }; ``` ##### 2. **queue(队列)** - **特性**:先进先出(FIFO),队尾插入、队头删除 - **底层容器**:需支持`push_back()`和`pop_front()`,默认使用`deque`,不可用`vector`(无`pop_front()`)[^1][^5] - **核心操作**: ```cpp queue<int> q; q.push(20); // 入队 $O(1)$ q.pop(); // 出队 $O(1)$ q.front(); // 队首元素 $O(1)$ ``` - **实现差异**: ```cpp template<class T, class Container = deque<T>> class queue { public: void pop() { _c.pop_front(); } // 依赖底层容器的头删操作 }; ``` ##### 3. **priority_queue(优先级队列)** - **特性**:元素按优先级排序,**堆结构**实现,默认大根堆 - **底层容器**:需支持随机访问(`operator[]`),默认使用`vector`,也可选`deque`[^4][^1] - **核心操作**: ```cpp priority_queue<int> pq; pq.push(30); // 插入 $O(\log n)$ pq.pop(); // 删除堆顶 $O(\log n)$ pq.top(); // 查看堆顶 $O(1)$ ``` - **堆维护**(引用[4]): ```cpp // 向下调整算法 void adjust_down(int parent) { size_t child = parent * 2 + 1; while (child < _con.size()) { if (child + 1 < _con.size() && _con[child] < _con[child+1]) ++child; if (_con[parent] < _con[child]) { swap(_con[parent], _con[child]); parent = child; child = parent * 2 + 1; } else break; } } ``` --- #### 三、底层容器选择对比 $$ \begin{array}{|l|c|c|c|} \hline \text{适配器} & \text{默认容器} & \text{可选容器} & \text{关键操作要求} \\ \hline stack & deque & vector/list & push_back/pop_back \\ queue & deque & list & push_back/pop_front \\ priority\_queue & vector & deque & 随机访问 + 堆操作 \\ \hline \end{array} $$ **为什么选择deque作为stack/queue默认容器?**[^2][^5] - 综合vector和list的优点 - 内存分段连续,扩容成本低 - 同时高效支持头尾操作 --- #### 四、应用场景 1. **stack**:函数调用栈、括号匹配、表达式求值 2. **queue**:消息队列、BFS算法、任务调度 3. **priority_queue**:任务优先级调度、Dijkstra算法、TopK问题 ```cpp // 示例:用stack实现括号匹配 bool is_valid(string s) { stack<char> st; for (char c : s) { if (c == '(' || c == '[') st.push(c); else { if (st.empty()) return false; if ((c == ')' && st.top() != '(') || (c == ']' && st.top() != '[')) return false; st.pop(); } } return st.empty(); } ``` --- #### 五、自定义适配器 可通过模板参数更换底层容器: ```cpp stack<int, list<int>> custom_stack; // 使用list实现的栈 priority_queue<int, vector<int>, greater<int>> min_heap; // 小根堆 ``` --- ### 相关问题 1. 为什么priority_queue默认使用vector而不是deque作为底层容器? 2. 如何用list实现queue适配器? 3. 容器适配器与直接使用底层容器的主要区别是什么? 4. stack的`top()`方法在不同底层容器下的时间复杂度是否相同? --- [^1]: 容器适配器基础特性与实现要求 [^2]: deque作为默认容器的优势分析 [^3]: stack/queue的底层容器限制 [^4]: priority_queue的堆维护算法 [^5]: queue的模拟实现示例
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值