目录
前言
一个容器就是一些特定类型对象的集合。顺序容器提供了控制元素存储和访问顺序的能力。这种顺序不依赖元素的值,而是与元素加入容器时的位置相对应。
一、顺序容器概述
vector | 可变大小数组。支持快速随机访问,在尾部之外的位置插入或删除元素可能很慢。 |
deque | 双端队列。支持快速随机访问。在头部和尾部插入或删除元素很快。 |
list | 双向链表。只支持双向顺序访问。在任意位置插入或删除都很快。 |
forward_list | 单向链表。只支持单向顺序访问。在任何位置插入或删除都很快。 |
array | 固定大小数组。支持快速随机访问。不能添加或删除元素。 |
string | 与vector相似的容器,但专门用于保存字符。随机访问快。在尾部插入或删除速度快。 |
二、通用容器操作
类别别名
iterator | 此容器类型的迭代其类型 |
const_iterator | 只读迭代器 |
size_type | 无符号整数类型,足够保存此容器类型最大可能容器的大小 |
difference_type | 带符号整数类型,足够保存两个迭代器之间的距离 |
value_type | 元素类型 |
reference | 元素左值类型;与value_type&含义相同 |
const_reference | 元素的const左值类型 |
构造函数
C c; | 默认构造函数,构造空容器 |
C c1(c2); | 构造c2拷贝c1 |
C c(b, e); | 构造c,将迭代器b和e指定范围内的元素拷贝到c(array不支持) |
C c{a, b, c, ...}; | 列表初始化c |
赋值与swap
c1 = c2; | 将c1元素替换为c2 |
c1 = {a, b, c, ...}; | 将c1元素替换为列表元素(array不支持) |
a.swap(b); | 交换a和b |
swap(a,b); | 交换a和b |
大小
c.size() | c中元素数目(forward_list不支持) |
c.max_size() | c中可保存的最大元素数目 |
c.empty() | 若c中有元素,则返回false;否则返回true |
添加/删除元素(array不支持)
c.insert(args); | 将args的元素拷贝进c |
c.emplace(inits); | 使用inits构造c中的一个元素 |
c.erase(args); | 删除args指定的元素 |
c.clear(); | 删除c的所有元素 |
获取迭代器
c.begin(), c.end() | 返回指向c的首元素和尾元素之后位置的迭代器 |
c.cbegin(), c.cend() | 返回const限制的迭代器 |
反向容器的额外成员(forward_list不支持)
reverse_iterator | 按逆序寻址元素的迭代器 |
const_reverse_iterator | const的逆序寻址元素的迭代器 |
c.rbegin(), c.rend() | 返回指向c的尾元素和首元素之前位置的迭代器 |
c.crbegin(), c.crend() | 返回const_reverse_iterator |
关系运算符
==, != | 所有容器均支持 |
< , <=, >, >= | 无序关联容器不支持 |
三、容器定义和初始化
C c; | 默认构造函数 |
C c1(c2); C c1 = c2; | c1初始化为c2的拷贝。c1和c2必须是相同类型。 |
C c{a, b, c, ...}; C c = {a, b, c, ...}; | c初始化为列表中元素的拷贝。列表中的元素必须与c的元素类型相容。 |
C c(b, e); | c初始化为迭代器b和e指定范围中的元素拷贝。 |
以下仅支持顺序容器,但不包括array | |
C seq(n) | seq包含n个元素,这些元素进行了值初始化 |
C seq(n, t) | seq包含n个初始化为值t的元素 |
例
list<string> authors = {"Milton", "Shakespeare", "Austen"};
vector<const char*> articles = {"a", "an", "the"};
list<string> list2(authors);//正确
deque<string> authlist(authors);//错误i
vector<string> words(articles);//错误
forward_list<string> words(articles.begin(), articles.end());//正确
//假定it指向authors的一个元素
deque<string> authlist(autnors.begin(), it);//正确
//与顺序容器有关的初始化
vector<int> ivec(10, -1);//10个int都是-1
list<string> svec(10, "hi!");//10个string都是"hi!"
forward_list<int> ivec(10);//10个int都是0
deque<string> svec(10);//10个string都是空
四、赋值与swap
c1 = c2 | 将c1元素替换为c2的拷贝。c1和c2同类型 |
c = {a, b, c, ...} | 将c中元素替换为初始化列表中元素的拷贝。 |
swap(c1, c2) c1.swap(c2) | 交换c1和c2。c1和c2必须同类型,速度较快 |
assign操作不适用于关联容器和array | |
seq.assign(b, e) | 将seq的元素替换为迭代器b和e所表示范围内的元素 |
seq.assign(il) | 将seq元素替换为初始化列表il的元素 |
seq.assign(n, t) | 将seq元素替换为n个值为t的元素 |
例
//assign允许从一个不同但相容的类型赋值,或者从容器的一个子序列赋值
list<string> names;
vector<const char*> oldstyle;
names = oldstyle;//错误
names.assign(oldstyle.cbegin(), oldstyle.cend());//正确
list<string> slist(1);
slist.assign(10, "hiya!");//正确
五、顺序容器
1.添加元素
array不支持以下任何操作。
forward_list有专有的insert和emplace,且不支持push_back和emplace_back。
vector和string不支持push_front和emplace_front。
c.push_back(t) c.emplace_back(args) | 在c的尾部创建一个值为t或由args创建的元素。返回void。 |
c.push_front(t) c.emplace_front(args) | 在c的头部创建一个值为t或由args创建的元素。返回void。 |
c.insert(p, t) c.emplace(p, args) | 在迭代器p指向的元素之前创建一个值为t或由args创建的元素。返回新添加元素的迭代器。 |
c.insert(p, n, t) | 在迭代器p指向的元素之前插入n个值为t的元素。返回指向新添加第一个元素的迭代器;若n为0,则返回p。 |
c.insert(p, b, e) | 将迭代器b和e指定的范围内的元素插入到迭代器p指向的元素之前。返回指向新添加第一个元素的迭代器;若范围为空,则返回p。 |
c.insert(p, il) | il是一个花括号包围的元素值列表。将这些给定值插入到迭代器p指向的元素之前。返回指向新添加第一个元素的迭代器;若列表为空,则返回p。 |
例
//在特定位置添加元素
vector<string> svec;
list<string> slist;
//等价slist.push_front("hello!");
slist.insert(slist.begin(), "hello!");
//vector等价push_front()形式,但速度可能很慢
svec.insert(svec.begin(), "hello!");
//插入范围内元素
//将10个anna插入到svec末尾
svec.insert(svec.end(), 10, "anna");
vector<string> v = {"qussi", "simba", "frollo", "scar"};
//将v最后两个元素添加到slist开始
slist.insert(slist.begin(), v.end()-2, v.end());
slist.insert(slist.end(), {"thses", "worsd", "will"});
slist.insert(slist.begin(), slist.begin(), slist.end());//错误,迭代器表示要拷贝范围,不能指向与目的位置相同的容器
//使用insert的返回值
list<string> lst;
auto iter = lst.begin();
while(cin >> word)
iter = lst.insert(iter, word);//相当于调用push_front
//当调用emplace函数时,则是将参数传递给元素类型的构造函数。
c.emplace_back("hello", 25, 19.22);
//等价于
c.push_back(sales_data("hello", 25, 19.22));
2.访问元素
at和下标操作只适用于vector, string, deque, array
back不适用于forward_list
c.back() | 返回c尾元素的引用,若c为空,则未定义 |
c.front() | 返回c头元素的引用,若c为空,则未定义 |
c[n] | 返回c中下标为n的引用,若n>=c.size(),则未定义 |
c.at(n) | 返回下标为n元素的引用,若越界则“out of range” |
例
if(!c.empty())
{
c.front() = 42;//将42赋值给第一个元素
auto &v = c.back();//获得指向最后一个元素的引用
v = 1024;//改变c的元素
auto v2 = c.back();//v2不是引用,他是c.back()的一个拷贝
v2 = 0;//未改变c中的元素
}
//安全访问
vector<string> svec;
cout << svec[0];//运行错误
cout << svec.at(0);//跑出out of range 异常
3.删除元素
这些操作会改变容器的大小,因此不适用于array
forward_list有特殊版本的erase,不支持pop_back
vector和string不支持pop_front
c.pop_back() | 删除尾元素。若为空则未定以。返回void。 |
c.pop_front() | 删除头元素。若为空则未定以。返回void。 |
c.erase(p) | 删除迭代器p指向的元素。返回指向被删元素之后元素的迭代器,若p为伪元素,则返回尾后迭代器。若p是尾后迭代器,则未定义。 |
c.erase(b, e) | 删除迭代器b和e所指范围内的元素。返回最后一个被删元素之后元素的迭代器。若e本身是尾后迭代器,则返回尾后迭代器。 |
c.clear() | 删除c中所有元素。返回void。 |
例
if(!ilist.empty())
{
ilist.pop_front();
}
//容器内删除元素,删除以下所有奇数
list<int> lst = {1, 2, 3, 4, 5, 6, 7, 8, 9};
auto it = lst.begin();
while(it != lst.end())
{
if(*it %2) it = lst.erase(it);
else ++it;
}
//删除多个元素
//elem1指向要删除的第一个元素,elem2指向要删除的最后一个元素之后的位置
elem = slist.erase(elem1, elem2);
总结
本篇总结了STL顺序容器的常用通用操作。