目录
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)
}