C++容器之双端队列(std::deque)

1 概述

  deque(通常发音像“deck”)是双端队列的一个不规则缩写。双端队列是具有动态大小的序列容器,可以在两端(前端或后端)进行扩展或收缩。
  特定的库可以以不同的方式实现deques,通常作为某种形式的动态数组。但在任何情况下,它们都允许通过随机访问迭代器直接访问单个元素,并根据需要通过扩展和收缩容器来自动处理存储。
  因此,它们提供了类似于矢量的功能,但也在序列的开始处,而不仅仅是在序列的结束处,有效地插入和删除元素。但是,与向量不同的是,deque不能保证将其所有元素存储在连续的存储位置:通过将指针偏移到另一个元素来访问deque中的元素会导致未定义的行为。
  vectors和deque都提供了非常相似的接口,可以用于类似的目的,但在内部都以完全不同的方式工作:虽然vectors使用一个偶尔需要重新分配才能增长的数组,但deque的元素可以分散在不同的存储块中,容器在内部保留必要的信息,以便在恒定时间内直接访问其任何元素,并具有统一的顺序接口(通过迭代器)。因此,deques的内部比向量复杂一点,但这使它们在某些情况下能够更有效地生长,尤其是在非常长的序列中,重新定位变得更加昂贵。
  对于涉及在除开头或结尾以外的位置频繁插入或删除元素的操作,与列表和前向列表相比,deques的性能更差,迭代器和引用的一致性也更低。

其类图如下:
类图

2 使用实例

void DequeSuite::push_back()
{
    int array[] = { 1, 2, 3, 4, 5 };
    std::deque<int> a;

    for(size_t i = 0; i < ARRAY_SIZE(array); i++)
        a.push_back(array[i]);

    for(size_t i = 0; i < a.size(); i++)
        TEST_ASSERT_EQUALS(array[i],  a[i])
}

void DequeSuite::push_front()
{
    int array[] = { 1, 2, 3, 4, 5 };
    std::deque<int> a;
    std::deque<int> b;

    for(size_t i = 0; i < ARRAY_SIZE(array); i++)
        a.push_front(array[i]);

    int index = 0;
    for(auto it = a.crbegin(); it != a.crend(); ++it)
        TEST_ASSERT_EQUALS(array[index++],  *it)
}

3 接口使用

3.1 construct

std::deque<int> getDeque(int size, int value)
{
    return std::deque<int>(size, value);
}
void DequeSuite::construct()
{
    std::deque<int> a;
    std::deque<int> b(4); // 0 0 0 0
    std::deque<int> c(4, 5);// 5 5 5 5
    std::deque<int> d({1, 2, 3, 4, 5});
    std::deque<int> e(d.begin(), d.end());
    std::deque<int> f(d);
    std::deque<int> g(getDeque(6, 8));

    TEST_ASSERT_EQUALS(0, a.size())
    TEST_ASSERT_EQUALS(4, b.size())
    TEST_ASSERT_EQUALS(4, c.size())
    TEST_ASSERT_EQUALS(5, d.size())
    TEST_ASSERT_EQUALS(5, e.size())
    TEST_ASSERT_EQUALS(5, f.size())
    TEST_ASSERT_EQUALS(6, g.size())
}

3.2 assigns

void DequeSuite::assigns()
{
    std::deque<int> a;
    std::deque<int> b;
    std::deque<int> c;
    a = { 1, 2, 3, 4, 5 };
    b = a;
    c = getDeque(5, 10);

    TEST_ASSERT_EQUALS(5, a.size())
    TEST_ASSERT_EQUALS(5, b.size())
    TEST_ASSERT_EQUALS(5, c.size())
}

3.3 iterators

#define ARRAY_SIZE(array) sizeof(array) / sizeof(array[0])
void DequeSuite::iterators()
{
    int  array[] = { 1, 2, 3, 4, 5 };
    int  rarray[] = { 5, 4, 3, 2, 1 };
    std::deque<int> a(array, array + ARRAY_SIZE(array));
    int index = 0;
    for(auto it = a.begin(); it != a.end(); ++it)
    {
        TEST_ASSERT_EQUALS(array[index++], *it)
    }
    
    index = 0;
    for(auto it = a.cbegin(); it != a.cend(); ++it)
    {
        TEST_ASSERT_EQUALS(array[index++], *it)
    }

    index = 0;
    for(auto it = a.rbegin(); it != a.rend(); ++it)
    {
        TEST_ASSERT_EQUALS(rarray[index], *it)
        rarray[index] = rarray[index] * 2;
        *it = rarray[index++];
    }
    
    index = 0;
    for(auto it = a.crbegin(); it != a.crend(); ++it)
    {
        TEST_ASSERT_EQUALS(rarray[index++], *it)
    }
}

3.4 capacity

void DequeSuite::capacity()
{
    std::deque<int> a;
    std::deque<int> b({1, 2, 3, 4, 5});
    TEST_ASSERT_EQUALS(0, a.size());
    TEST_ASSERT_EQUALS(5, b.size());
    TEST_ASSERT_EQUALS(true, a.empty());
    TEST_ASSERT_EQUALS(false, b.empty());

    TEST_ASSERT_EQUALS(a.max_size(), b.max_size());
}

3.5 rezize

void DequeSuite::rezize()
{
    std::deque<int> a;
    a.resize(5, 10);  //10 10 10 10 10
    for(auto it = a.begin(); it != a.end(); ++it)
        TEST_ASSERT_EQUALS(10, *it);
    a.resize(8);      //10 10 10 10 10 0 0 0
    for(auto it = a.begin(); it != a.begin() + 5; ++it)
        TEST_ASSERT_EQUALS(10, *it);
    for(auto it = a.begin() + 5; it != a.end(); ++it)
        TEST_ASSERT_EQUALS(0, *it);
    a.resize(10, 20); //10 10 10 10 10 0 0 0 20 20
    for(auto it = a.begin() + 10; it != a.end(); ++it)
        TEST_ASSERT_EQUALS(20, *it);
}

3.6 shrink_to_fit

void DequeSuite::shrink_to_fit()
{
    std::deque<int> a (100);
    TEST_ASSERT_EQUALS(100, a.size())
    a.resize(10);
    TEST_ASSERT_EQUALS(10, a.size())
    a.shrink_to_fit();
}

说明:

  • 该函数不修改size大小

3.7 access

void DequeSuite::access()
{
    int  array[] = { 1, 2, 3, 4, 5 };
    std::deque<int> a(array, array + ARRAY_SIZE(array));
    

    TEST_ASSERT_EQUALS(1, a.front())//size of a must more than 0
    TEST_ASSERT_EQUALS(5, a.back()) //size of a must more than 0

    for(size_t i = 0; i < a.size(); i++)
    {
        TEST_ASSERT_EQUALS(array[i], a[i])
         array[i] = a[i] * 2;
        a[i] = array[i];
    }
    TEST_ASSERT_EQUALS(2, a.front())
    TEST_ASSERT_EQUALS(10, a.back())

    for(size_t i = 0; i < a.size(); i++)
    {
        TEST_ASSERT_EQUALS(array[i], a.at(i))
        array[i] = a.at(i) / 2;
        a.at(i) = array[i];
    }
    TEST_ASSERT_EQUALS(1, a.front())
    TEST_ASSERT_EQUALS(5, a.back())

    bool hasExcpetion = false;
    try {
        int v = a.at(6);
    }
    catch(...)
    {
        hasExcpetion = true;
    }
    TEST_ASSERT_EQUALS(true, hasExcpetion)
}

3.8 assign

void DequeSuite::assign()
{
    std::deque<int> a;
    std::deque<int> b;
    std::deque<int> c;
    a.assign({ 1, 2, 3, 4, 5 });
    b.assign(a.begin(), a.end());
    c.assign(4, 5);

    TEST_ASSERT_EQUALS(5, a.size())
    TEST_ASSERT_EQUALS(5, b.size())
    TEST_ASSERT_EQUALS(4, c.size())
}

3.9 push_back

void DequeSuite::push_back()
{
    int array[] = { 1, 2, 3, 4, 5 };
    std::deque<int> a;

    for(size_t i = 0; i < ARRAY_SIZE(array); i++)
        a.push_back(array[i]);

    for(size_t i = 0; i < a.size(); i++)
        TEST_ASSERT_EQUALS(array[i],  a[i])
}

3.10 push_front

void DequeSuite::push_front()
{
    int array[] = { 1, 2, 3, 4, 5 };
    std::deque<int> a;
    std::deque<int> b;

    for(size_t i = 0; i < ARRAY_SIZE(array); i++)
        a.push_front(array[i]);

    int index = 0;
    for(auto it = a.crbegin(); it != a.crend(); ++it)
        TEST_ASSERT_EQUALS(array[index++],  *it)
}

说明:

  • 相对vector,deque可以从front插入元素

3.11 pop_back

void DequeSuite::pop_back()
{
    std::deque<int> a({1, 2, 3, 4, 5});

    TEST_ASSERT_EQUALS(5, a.back())

    a.pop_back();
    TEST_ASSERT_EQUALS(4, a.back())
    
    a.pop_back();
    TEST_ASSERT_EQUALS(3, a.back())

    a.pop_back();
    TEST_ASSERT_EQUALS(2, a.back())
    
    a.pop_back();
    TEST_ASSERT_EQUALS(1, a.back())

    a.pop_back();
    TEST_ASSERT_EQUALS(true, a.empty())

    if(!a.empty())
        a.pop_back();//??
    TEST_ASSERT_EQUALS(true, a.empty())
}

3.12 pop_front

void DequeSuite::pop_front()
{
    std::deque<int> a({1, 2, 3, 4, 5});

    TEST_ASSERT_EQUALS(1, a.front())

    a.pop_front();
    TEST_ASSERT_EQUALS(2, a.front())
    
    a.pop_front();
    TEST_ASSERT_EQUALS(3, a.front())

    a.pop_front();
    TEST_ASSERT_EQUALS(4, a.front())
    
    a.pop_front();
    TEST_ASSERT_EQUALS(5, a.front())

    a.pop_front();
    TEST_ASSERT_EQUALS(true, a.empty())

    if(!a.empty())
        a.pop_front();//??
    TEST_ASSERT_EQUALS(true, a.empty())
}

说明:

  • 相对vector,deque可以从front弹出元素

3.13 insert

void DequeSuite::insert()
{
    std::deque<std::string> names;
    std::string name("James");

    auto it = names.insert(names.begin(), name);//James
    TEST_ASSERT_EQUALS(name, *it)

    it = names.insert(names.end(), 2, "Tom"); //James Tom Tom 
    TEST_ASSERT_EQUALS("Tom", *it)

    it = names.insert(names.end(), "Peter"); //James Tom Tom Peter
    TEST_ASSERT_EQUALS("Peter", *it)

    it = names.insert(names.end(), {"Jim", "Rose", }); //James Tom Tom Peter Jim Rose
    TEST_ASSERT_EQUALS("Jim", *it)
}

说明:

  • 返回iterator指向被删除元素的下一位置

3.14 erase

void DequeSuite::erase()
{
    std::deque<int> a({1, 2, 3, 4, 5});
    TEST_ASSERT_EQUALS(5, a.back())
    
    auto it = a.erase(a.begin() + 4);//1, 2, 3, 4

    //a.erase(a.begin() + 5); double free or corruption (out)

    TEST_ASSERT_EQUALS(true, it == a.end())
    TEST_ASSERT_EQUALS(4, a.back())

    it = a.erase(a.begin() + 1, a.begin() + 3);//1, 4
    TEST_ASSERT_EQUALS(4, *it)
    TEST_ASSERT_EQUALS(4, a.back())
}

说明:

  • 传入iterator必须是有效的
  • 返回iterator指向被删除元素的下一位置

3.15 swap

void DequeSuite::swap()
{
    std::deque<int> a({1, 2, 3, 4, 5});
    std::deque<int> b;

    TEST_ASSERT_EQUALS(5, a.size())
    TEST_ASSERT_EQUALS(0, b.size())

    a.swap(b);
    TEST_ASSERT_EQUALS(0, a.size())
    TEST_ASSERT_EQUALS(5, b.size())
}

3.16 clear

void DequeSuite::clear()
{
    std::deque<int> a({1, 2, 3, 4, 5});

    TEST_ASSERT_EQUALS(5, a.size())
    a.clear();

    TEST_ASSERT_EQUALS(0, a.size())
}

3.17 emplace

void DequeSuite::emplace()
{
    std::deque<std::string> names;
    auto it = names.emplace(names.begin(), "james"); //james
    TEST_ASSERT_EQUALS("james", *it)
    it = names.emplace(names.end(), "jim"); //james jim
    TEST_ASSERT_EQUALS("jim", *it)
}

说明:

  • 返回iterator指向被删除元素的下一位置

3.18 emplace_front

void DequeSuite::emplace_front()
{
    std::deque<std::string> names;
    names.emplace_front("james"); //james
    TEST_ASSERT_EQUALS("james", names.front())
    names.emplace_front("jim"); //james jim
    TEST_ASSERT_EQUALS("jim", names.front())
}

说明:

  • 返回iterator指向被删除元素的下一位置

3.19 emplace_back

void DequeSuite::emplace_back()
{
    std::deque<std::string> names;
    names.emplace_back("james"); //james
    TEST_ASSERT_EQUALS("james", names.back())
    names.emplace_back("jim"); //james jim
    TEST_ASSERT_EQUALS("jim", names.back())
}

3.20 get_allocator

void DequeSuite::get_allocator()
{
    std::deque<int> a;
    auto allocator = a.get_allocator();
    int* p = allocator.allocate(5);

    allocator.deallocate(p, 5);
    try
    {
        p = allocator.allocate(allocator.max_size() + 1);
    }
    catch(...)
    {
        p = nullptr;
    }
    TEST_ASSERT_EQUALS(true, p == nullptr)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

flysnow010

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

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

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

打赏作者

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

抵扣说明:

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

余额充值