C++回顾之顺序容器

  1. 顺序容器类型:vector deque(双端队列,也可快速随机访问)list(双向链表)forward_list(单向链表) array(比内置数组更安全) string

  2. string 和 vector 都是将元素保存在连续的内存空间。快速随机访问,但插入删除就很慢。

  3. 应该使用标准庫容器,而不是原始的数据结构,如内置数组。

  4. 元素初始化器(295页)

  5. forward_list迭代器不支持递减运算符。

  6. 容器操作可能使得迭代器操作失效。


vector对象的增长

vector对象是连续存储的,当它预留的空间不够使用时则必须将全部元素迁移到新的更大的空间上。vector只有在迫不得已的时候才会分配新的内存空间。

vector<int> c;
c.capacity() // 不重新分配内存的话,c可以保存多少元素
c.reserve(n) // 分配至少能容纳n个元素的空间

三个顺序容器适配器:stack(默认基于deque), queue(默认基于deque), priority_queue(默认基于vector)。

一个容器适配器接受一种已有的容器类型,使其行为看起来像一种不同的类型。

每个适配器都基于底层容器类型的操作定义了自己的特殊操作。

<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的模拟实现示例
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值