deque(n):双端队列
emplace(v):安放
assign(v):分配、布置
1 顺序容器
一个容器是一些特定类型对象的集合。
容器是标准库中提供的数据结构(本质是数组扩展的vector、deque、array、string 和 指针扩展的list、forward_list)
顺序容器提供控制元素存储和访问顺序的能力,这种顺序与元素加入容器时的位置相对应。
![在这里插入图片描述](https://img-blog.csdnimg.cn/c3e05a15a5c243668f59833eb015f20d.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDQ3ODY1OQ==,size_16,color_FFFFFF,t_70)
2 顺序容器的接口(详见P295)
①构造函数:
C c;
C c1(c2); //构造c2的拷贝-c1
C c(b, e); //迭代器b和e范围内的元素拷贝到c
C c(a, b, c);//列表初始化c
②赋值函数:
c.assign(b, e);
c1 = c2;
c1 = {a, b, c...};//不适用于列表元素
a.swap(b);//交换a和b的元素
swap(a, b);
③获取迭代器:
返回指向c的首元素和尾元素之后位置的迭代器,因为对于容器迭代器区间是[begin,end)左闭右开的。
c.begin(), c.end()
返回const_iterator
c.cbegin(), c.cend()
3 反向迭代器:
反向迭代器详解
①反向迭代器的模板类定义在 < iterator> 头文件,并位于 std 命名空间中。
reverse_iterator //按逆序寻址元素的迭代器
const_reverse_iterator //不能修改元素的逆序迭代器
c.rbegin() //返回一个逆序迭代器,指向容器c的最后一个元素
c.crend() // 返回一个逆序迭代器,它指向容器c的第一个元素前面的位置
c.crbegin(),c.crend() //返回const_reverse_iterator
②反向迭代器自带base()函数,其基准迭代器为正序,且向右偏移1个元素
s.rbegin().base() == s.end()
s.rend().base() == s.begin()
③除了常规的正/反向迭代器begin()、end()、rbegin()、rend()、crbegin()、crend()外,可以通过find函数找到元素,并定义正/反向迭代器指向它
string::reverse_iterator rcomma = find(line.rbegin(), line.rend(), ',');
④反向迭代器++,迭代器逆序前进1
⑤利用反向迭代器逆序排列
// sorts vec in "normal" order
sort(vec.begin(), vec.end());
// sorts in reverse: puts smallest element at the end of vec
sort(vec.rbegin(), vec.rend());
4 顺序容器操作实例
#include <iostream>
#include <list>
#include <deque>
using namespace std;
template <class T>
void printContainer(const char* msg, const T& s) {
cout << msg << ": ";
copy(s.begin(), s.end(), ostream_iterator<int>(cout, " ")); //输出流需要指定类型<int/double>
//copy(迭代器左区间, 迭代器右区间, 容器中迭代器区间的全部元素复制到“标准输出流”中)
cout << endl;
}
int main() {
deque<int> s;
for (int i = 0; i < 10; i++) {
int x;
cin >> x;
s.push_front(x);
}
printContainer("deque at first: ", s); //由于把元素加到s队列的头部,s中元素是逆序的
list<int> l(s.rbegin(), s.rend());//rbegin()->rend()是把原队列尾作为头,原队列头作为尾,逆序取元素
printContainer("list at first: ", l);
list<int>::iterator iter = l.begin();//注意这种定义方式,定义列表的迭代器iter
while (iter != l.end()) { //将列表l的相邻两个元素交换
int v = *iter;
iter = l.erase(iter);//erase擦除iter迭代器对应的元素,返回下一个元素的地址
l.insert(++iter, v);//++iter使迭代器再后移,此时指向初始位置的后面的后面的元素
//insert是在迭代器指向的元素前面插入一个元素,此时迭代器还是指向第三个元素
}
printContainer("list at last: ", l);
s.assign(l.begin(), l.end()); //通过assgin函数将列表l迭代器之间的元素复制给队列s
//在不能使用赋值符“ = ”的情况下,可以将一个容器中的部分元素通过迭代器传递赋值到另一个容器中,
//但是在assign的使用过程中,有一点需要特别注意,就是调用assign()函数的容器必须有足够的空间来容纳复制过来的元素
printContainer("deque at last: ", s);
return 0;
}
TIPS:
不用常规方法交换相邻元素是因为迭代器只是泛型的指针,未重载时不能像普通指针一样使用+、=等运算符。
通常使用迭代器特殊函数进行运算。
以下不可行:
while (iter != l.end()) {
int v = *iter;
*iter = *(iter + 1);
*(iter + 1) = v;
iter += 2;
}
5 顺序容器的特征(vector、deque、list、forward_list、array)
向量与双端队列
随机访问速度:vector > deque > > list/forward_list
vector在尾部插入/删除元素快,deque在头部和尾部插入/删除元素快.
vector、deque在中间插入/删除元素慢,list/forward_list在任何位置插入/删除元素快
#include <iostream>
#include <vector>
#include <deque>
#include <algorithm>
using namespace std;
int main() {
istream_iterator<int> i1(cin), i2;
vector<int> s1(i1, i2); //通过迭代器构造
sort(s1.begin(), s1.end());//正向排序,在algorithm头文件中
deque<int> s2;
for (vector<int>::iterator iter = s1.begin(); iter != s1.end(); ++iter) {
//注意指明是哪个容器的迭代器
if (*iter % 2 == 0) {
s2.push_back(*iter);
}
else
s2.push_front(*iter);
}
copy(s2.begin(), s2.end(), ostream_iterator<int>(cout, " "));
//注意输入、输出流迭代器都要指定数据类型
//copy函数把容器元素放到输出流中
cout << endl;
return 0;
}
链表
#include <iostream>
#include <string>
#include <list>
#include <iterator>
using namespace std;
int main()
{
string names1[] = { "Alice", "Helen", "Lucy", "Susan" };
string names2[] = { "Bob", "David", "Levin", "Mike" };
list<string> s1(names1, names1 + 4);
list<string>s2(names2, names2 + 4);
s2.splice(s2.end(), s1, s1.begin());//如果只写begin(),只拼接链表首元素
list<string>::iterator iter1 = s1.begin();//通过创建链表迭代器来控制
advance(iter1, 2); //迭代器1前进两个部分
list<string>::iterator iter2 = s2.begin();
++iter2; //迭代器++或者前进均可
list<string>::iterator iter3 = iter2;
advance(iter3, 2);
s1.splice(iter1, s2, iter2, iter3);
copy(s1.begin(), s1.end(), ostream_iterator<string>(cout, " ")); //copy到输出流
cout << endl;
copy(s2.begin(), s2.end(), ostream_iterator<string>(cout, " "));
cout << endl;
return 0;
}