C++开发必备之stl进阶(四deque)

双端队列deque

std::deque(双端队列,Double-ended Queue)是 C++ 标准模板库(STL)中的一种序列容器,允许在两端(前端和后端)高效地插入和删除元素。deque 提供了与 std::vector 类似的功能,但 deque 支持在容器的头部和尾部同时进行高效的插入和删除操作,而 vector 在头部插入元素时效率较低,因为它需要移动所有元素。

1. std::deque 的特点

  • 动态大小:与 std::vector 类似,std::deque 的大小可以动态调整。
  • 高效的双端操作deque 支持在头部和尾部进行常数时间(O(1))的插入和删除操作。
  • 随机访问:与 std::vector 一样,deque 支持常数时间(O(1))的随机访问。
  • 灵活的内存管理deque 不是像 vector 那样的连续内存块,它的底层实现通常由多个连续的小块内存组成,因此它的内存分配更加灵活。

2. std::deque 的用法

2.1 初始化 std::deque

std::deque 支持多种初始化方式:

#include <iostream>
#include <deque>

int main() {
    // 默认构造空双端队列
    std::deque<int> dq1;

    // 使用初始值构造
    std::deque<int> dq2(5, 10);  // 5 个元素,值为 10

    // 使用列表初始化
    std::deque<int> dq3 = {1, 2, 3, 4, 5};

    // 拷贝构造
    std::deque<int> dq4(dq3);

    // 输出 deque 的内容
    for (int n : dq3) {
        std::cout << n << " ";  // 输出: 1 2 3 4 5
    }

    return 0;
}
2.2 插入和删除操作

std::deque 提供了多种操作来支持在头部和尾部插入和删除元素。

6. 适用场景

5. std::dequestd::vector 的区别

  • push_back():在末尾插入元素。
  • push_front():在头部插入元素。
  • pop_back():删除末尾元素。
  • pop_front():删除头部元素。
    #include <iostream>
    #include <deque>
    
    int main() {
        std::deque<int> dq;
    
        // 在队列末尾添加元素
        dq.push_back(10);
        dq.push_back(20);
    
        // 在队列头部添加元素
        dq.push_front(30);
        dq.push_front(40);
    
        // 输出 deque 的内容
        for (int n : dq) {
            std::cout << n << " ";  // 输出: 40 30 10 20
        }
    
        // 删除头部和尾部的元素
        dq.pop_front();
        dq.pop_back();
    
        std::cout << "\nAfter pop operations: ";
        for (int n : dq) {
            std::cout << n << " ";  // 输出: 30 10
        }
    
        return 0;
    }
    
    2.3 随机访问

    std::vector 类似,deque 也支持常数时间的随机访问,使用下标运算符 []at() 来访问特定位置的元素。

    #include <iostream>
    #include <deque>
    
    int main() {
        std::deque<int> dq = {10, 20, 30, 40};
    
        // 使用下标运算符访问元素
        std::cout << "Element at index 1: " << dq[1] << std::endl;  // 输出: 20
    
        // 使用 at() 访问元素
        std::cout << "Element at index 3: " << dq.at(3) << std::endl;  // 输出: 40
    
        return 0;
    }
    
    2.4 大小与容量操作

    std::deque 提供了一些方法来检查容器的大小、是否为空等。

  • size():返回容器中的元素数量。
  • empty():检查容器是否为空。
  • resize():调整容器大小。
    #include <iostream>
    #include <deque>
    
    int main() {
        std::deque<int> dq = {1, 2, 3};
    
        std::cout << "Size: " << dq.size() << std::endl;  // 输出: 3
    
        // 调整大小
        dq.resize(5, 10);  // 将大小调整为 5,新增元素值为 10
        std::cout << "After resizing: ";
        for (int n : dq) {
            std::cout << n << " ";  // 输出: 1 2 3 10 10
        }
    
        return 0;
    }
    

    3. 高级操作

    3.1 插入与删除

    std::deque 允许在任意位置插入或删除元素,使用 insert()erase() 函数。

    #include <iostream>
    #include <deque>
    
    int main() {
        std::deque<int> dq = {1, 2, 3, 4, 5};
    
        // 在第三个位置插入元素
        dq.insert(dq.begin() + 2, 100);  // {1, 2, 100, 3, 4, 5}
    
        // 删除第三个位置的元素
        dq.erase(dq.begin() + 2);  // {1, 2, 3, 4, 5}
    
        // 删除范围内的元素
        dq.erase(dq.begin(), dq.begin() + 2);  // {3, 4, 5}
    
        for (int n : dq) {
            std::cout << n << " ";  // 输出: 3 4 5
        }
    
        return 0;
    }
    
    3.2 迭代器支持

    std::deque 支持迭代器,可以使用标准的迭代器操作来遍历 deque。此外,deque 还支持反向迭代器。

    #include <iostream>
    #include <deque>
    
    int main() {
        std::deque<int> dq = {10, 20, 30, 40};
    
        // 正向遍历
        std::cout << "Forward iteration: ";
        for (auto it = dq.begin(); it != dq.end(); ++it) {
            std::cout << *it << " ";  // 输出: 10 20 30 40
        }
    
        // 反向遍历
        std::cout << "\nReverse iteration: ";
        for (auto rit = dq.rbegin(); rit != dq.rend(); ++rit) {
            std::cout << *rit << " ";  // 输出: 40 30 20 10
        }
    
        return 0;
    }
    
    3.3 双端队列与 std::queue 适配器

    std::dequestd::queue 容器适配器的默认底层容器。通过 std::queue,可以利用 deque 的双端性质来实现标准队列行为。

    #include <iostream>
    #include <deque>
    #include <queue>
    
    int main() {
        std::queue<int> q;
    
        q.push(1);  // 插入元素
        q.push(2);
        q.push(3);
    
        std::cout << "Front element: " << q.front() << std::endl;  // 输出: 1
        std::cout << "Back element: " << q.back() << std::endl;    // 输出: 3
    
        q.pop();  // 移除前端元素
    
        std::cout << "After pop, front element: " << q.front() << std::endl;  // 输出: 2
    
        return 0;
    }
    

    4. std::deque 的效率与实现

  • std::deque 在头部和尾部的插入和删除操作的效率是 O(1) 的,因为它不需要像 vector 那样进行大量的数据移动。
  • 由于 deque 并不是一个连续的内存块,它由一系列小的内存块(称为缓冲区)组成,因此在内存管理上更灵活,适合频繁在两端进行插入和删除的操作。
  • 随机访问 deque 中的元素是 O(1) 的,这使得它与 vector 类似,可以进行高效的下标访问。
  • 内存结构std::vector 是一个连续的内存块,而 std::deque 则是由多个小内存块组成。
  • 插入和删除操作std::deque 支持在头部和尾部进行高效的插入和删除操作,而 std::vector 只在尾部具有这种高效性,头部插入会导致所有元素移动。
  • 内存重分配std::vector 在内存不足时需要重分配整个数组,而 std::deque 可以通过动态增加内存块来扩展容量,因此减少了大规模的内存拷贝。
  • 需要双端操作:如果你需要在容器的头部和尾部都进行频繁的插入或删除操作,std::deque 是一个很好的选择。
  • 需要随机访问:如果需要支持随机访问并且需要双端操作,std::deque 也是一个不错的选择。
  • 不适合:如果只需要在末尾插入或删除大量元素并进行连续的访问,std::vector 可能是更好的选择,因为它在尾部操作上的性能与 deque 相当,但在空间利用率上更为紧凑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值