想必读到这里的宝宝们应该已经读过了介绍vector和list容器的两篇文章,在处理数据对象时,vector、list、deque是三个最常用的序列式容器
所以我想把三个常用的序列式容器放在一起对比一下是有必要的:
(1)vector容器
vector又被称为动态数组,它拥有一段连续的内存空间,能非常好的支持随机存取,即可以使用[]操作符。
但由于它的内存空间是连续的,所以在中间进行插入和删除会造成内存块的拷贝,另外,当插入较多的元素后,预留内存空间可能不够,需要重新申请一块足够大的内存并把原来的数据拷贝到新的内存空间。
这些因素影响了vector的效率,但是实际上用的最多的还是vector容器,大多数时候使用vector效率一般是不错的。
(2)list容器
list的本质其实就是数据结构中的双向链表(从STL源代码中可以明确看出),因此它的内存空间是不连续的,只能通过指针来进行数据的访问。
这个特点使得它的随机存取变的非常没有效率,因此它没有提供[]操作符的重载。但由于链表的特点,它可以以很好的效率支持任意地方的删除和插入。
(3)deque容器
deque的本质是数据结构中的双端队列(具体实现我也不太清楚,想了解的话可以去阅读STL源码),但是它有两个鲜明的特点:
1.它支持[]操作符,也就是像vector那样随机存取,并且和vector的效率相差无几
2.它支持在两端的操作:即push_back(),push_front(),pop_back(),pop_front(),并且在两端操作上与list的效率也差不多。
当我们在实际编程需要使用时,应该选择这三个容器中哪一个,要根据当前的需求而定,具体可以遵循下面的原则:
1. 如果你需要高效的随机存取,而不在乎插入和删除的效率,使用vector
2. 如果你需要大量的插入和删除,而不关心随机存取,则应使用list
3. 如果你需要随机存取,而且关心两端数据的插入和删除,则应使用deque
下面将介绍deque容器的一些常见用法,其实几乎所有的操作都是和vector一模一样的,除了不提供容量操作【如capacity()、reserve()】
1.在deque两端插入元素
dq.push_front(5); //在队首加入元素
dq.emplace_front(5); //在队首加入元素
dq.emplace_back(5); //在队尾加入元素
dq.push_back(6); //在队尾加入元素
2.在deque中间插入元素
deque<int> dq = {1, 2, 3, 4, 5};
dq.insert(dq.begin(), 6); //在开头插入6
dq.insert(dq.begin(), 3, 7); //在开头插入三个7
dq.insert(dq.begin() + 4, 8); //在第四位插入8,也即插入后8成为第五位
dq.insert(dq.begin() + 6, 5, 0); //在第六位插入五个0,也即插入后从第七位开始有连续的五个0
3.deque删除最后一个元素
dq.pop_back();
4.deque删除某一指定位置元素
(1)删除开头第一个元素
dq.erase(dq.begin());
(2)使用迭代器删除第四个元素
deque<int>::iterator it = dq.begin()+3;
dq.erase(it);
(3)不使用迭代器删除第四个元素
dq.erase(dq.begin() + 3);
5.deque删除某一范围内的元素
dq.erase(dq.begin() + 2, dq.begin() + 5); //左闭右开,实际上就是删除下标为[2,4]的元素
6.deque删除某一指定值元素
dq.erase(remove(dq.begin(), dq.end(), 0), dq.end()); //删除双端队列中所有的0
7.清空整个deque
dq.clear();
8.判断deque是否为空
dq.empty();
9.deque中查找某一元素
deque<int> dq = {1, 2, 3, 4, 5};
deque<int>::iterator it = find(dq.begin(), dq.end(), 6);
if (it != dq.end()) cout << "Yes";
else cout << "No";
//如果迭代器的返回值为dq.end(),则表示查找失败,否则表示查找成功,此例子中明显查找不到,所以输出为NO
10.对deque进行排序
sort(dq.begin(), dq.end()); //从小到大排序
sort(dq.begin(), dq.end(), greater<int>()); //从大到小排序
sort(dq.begin(), dq.end(), cmp); //对deque自定义排序,cmp为你自己定义的排序函数(准则)
11.对deque进行遍历
//使用下标进行遍历(正序)
for (int i = 0; i <= dq.size(); i++) cout << dq[i] << " ";
//使用下标进行遍历(逆序)
for (int i = dq.size() - 1; i >= 0; i--) cout << dq[i] << " ";
//对于deque来说不是很推荐使用迭代器进行遍历,所以就不介绍了
12.交换两个deque
dq1.swap(dq2);
//下面这种写法也可以
swap(dq1, dq2);
13.将两个无序deque合并为一个有序deque
dq1.insert(dq1.end(), dq2.begin(), dq2.end());
sort(dq1.begin(), dq1.end());