好的!既然你提到了 C++ 标准库中的容器类 <deque>,我将为你详细讲解它的用法,包括基本概念、特性、功能以及实用示例。<deque>(双端队列,double-ended queue)是 C++ STL 中的一种动态容器,结合了 <vector><list> 的优点,支持高效的首尾操作和随机访问。以下是完整的内容,适合学习和实践。


C++ 标准库:<deque>

<deque> 是一个模板类,表示双端队列。它的主要特点是:

  • 动态大小:可以在运行时添加或删除元素。
  • 高效首尾操作:在头部和尾部插入/删除元素的时间复杂度为 O(1)。
  • 随机访问:支持通过索引快速访问元素,类似 <vector>
  • 分块内存:内部使用分块连续内存(非单一连续块),兼顾效率和灵活性。

包含头文件

#include <deque>
#include <iostream> // 通常配合使用

定义格式

std::deque<类型> 变量名;
  • 类型:元素的数据类型(如 intdoublestd::string)。
  • 可选:初始大小或初始化列表。

基本用法

1. 声明和初始化

#include <deque>
#include <iostream>

int main() {
    std::deque<int> deq1;               // 空双端队列
    std::deque<int> deq2(5, 10);        // 5 个元素,每个值为 10
    std::deque<int> deq3 = {1, 2, 3, 4}; // 初始化列表(C++11 起)

    std::cout << "deq3: ";
    for (int val : deq3) {
        std::cout << val << " ";
    }
    std::cout << std::endl; // 输出:1 2 3 4
    return 0;
}

2. 添加和删除元素

#include <deque>
#include <iostream>

int main() {
    std::deque<int> deq;
    deq.push_back(10);  // 在末尾添加
    deq.push_front(20); // 在开头添加
    deq.push_back(30);

    std::cout << "Original: ";
    for (int val : deq) {
        std::cout << val << " "; // 输出:20 10 30
    }
    std::cout << std::endl;

    deq.pop_front(); // 删除开头元素
    deq.pop_back();  // 删除末尾元素
    std::cout << "After pop: ";
    for (int val : deq) {
        std::cout << val << " "; // 输出:10
    }
    std::cout << std::endl;

    return 0;
}
  • push_back() / push_front():O(1) 复杂度。
  • pop_back() / pop_front():O(1) 复杂度。

3. 访问元素

#include <deque>
#include <iostream>

int main() {
    std::deque<double> deq = {1.5, 2.7, 3.9};
    std::cout << "First: " << deq[0] << std::endl;      // 下标访问
    std::cout << "Second: " << deq.at(1) << std::endl;  // 边界检查访问
    std::cout << "Front: " << deq.front() << std::endl; // 第一个元素
    std::cout << "Back: " << deq.back() << std::endl;   // 最后一个元素
    return 0;
}

输出:

First: 1.5
Second: 2.7
Front: 1.5
Back: 3.9
  • []:无边界检查,O(1)。
  • at():有边界检查,O(1),超界抛出 std::out_of_range

4. 大小和容量

#include <deque>
#include <iostream>

int main() {
    std::deque<int> deq = {1, 2, 3};
    std::cout << "Size: " << deq.size() << std::endl;         // 当前元素数:3
    std::cout << "Max size: " << deq.max_size() << std::endl; // 最大可能大小
    std::cout << "Empty? " << (deq.empty() ? "Yes" : "No") << std::endl; // 是否为空:No
    return 0;
}
  • size():O(1)。
  • capacity(),但可用 shrink_to_fit()(C++11)减少多余空间。

5. 插入和删除

#include <deque>
#include <iostream>

int main() {
    std::deque<int> deq = {1, 2, 3, 4};
    deq.insert(deq.begin() + 1, 99); // 在第 2 个位置插入 99
    std::cout << "After insert: ";
    for (int val : deq) {
        std::cout << val << " "; // 输出:1 99 2 3 4
    }
    std::cout << std::endl;

    deq.erase(deq.begin()); // 删除第一个元素
    std::cout << "After erase: ";
    for (int val : deq) {
        std::cout << val << " "; // 输出:99 2 3 4
    }
    std::cout << std::endl;

    return 0;
}
  • insert() / erase():中间操作 O(n),首尾 O(1)。

6. 迭代器

#include <deque>
#include <iostream>

int main() {
    std::deque<std::string> deq = {"Apple", "Banana", "Orange"};
    std::cout << "Forward: ";
    for (auto it = deq.begin(); it != deq.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl; // 输出:Apple Banana Orange

    std::cout << "Reverse: ";
    for (auto it = deq.rbegin(); it != deq.rend(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl; // 输出:Orange Banana Apple
    return 0;
}
  • 支持随机访问迭代器:begin()/end()rbegin()/rend()

与其他容器的对比

特性std::dequestd::vectorstd::list
内存布局分块连续单一连续非连续(链表)
首尾插入/删除O(1)尾 O(1),首 O(n)O(1)
中间插入/删除O(n)O(n)O(1)
随机访问O(1)O(1)不支持
内存开销中等较低较高

注意事项

  1. 性能:首尾操作高效,中间操作较慢。
  2. 迭代器失效:插入/删除可能导致迭代器失效(首尾操作除外)。
  3. 内存:分块存储比 <vector> 多些开销,但比 <list> 少。
  4. 应用场景:适合队列、双端栈,或需要快速首尾访问的场景。

小练习

以下是一个基于 <deque> 的练习题,你可以尝试:

问题:

写一个 C++ 程序:

  1. 定义一个 std::deque<int>,初始化为 {1, 2, 3, 4, 5}。
  2. 在开头插入 99。
  3. 在末尾插入 100。
  4. 删除第 3 个元素(值为 3)。
  5. 输出所有元素和当前大小。

参考答案(你可以先尝试)

#include <deque>
#include <iostream>

int main() {
    std::deque<int> deq = {1, 2, 3, 4, 5};

    // 在开头插入 99
    deq.push_front(99);

    // 在末尾插入 100
    deq.push_back(100);

    // 删除第 3 个元素(索引 2)
    deq.erase(deq.begin() + 2);

    // 输出所有元素和大小
    std::cout << "Elements: ";
    for (int val : deq) {
        std::cout << val << " ";
    }
    std::cout << "\nSize: " << deq.size() << std::endl;

    return 0;
}

输出:

Elements: 99 1 2 4 5 100
Size: 6

下一步

  • 如果你想试试这个练习,请写下你的代码,我会帮你检查。
  • 如果你想要更复杂的内容(如实现滑动窗口、双端队列应用),或者设计 <deque> 的测验题,请告诉我!
  • 你也可以提出具体问题,如“如何用 <deque> 实现队列?”或“<deque> 的内存分配原理?”。

现在,你想做什么?试试练习,还是有其他需求?