👉目录👈
1. 容器类型的限制
//假定noDefault没有默认构造函数
vector<noDefault> v1(10); //错误,必须提供一个元素初始化器
vector<noDefault> v1(10,init); //正确,可以自己提供元素初始化器
2.容器操作
//类型别名
difference_type //带符号整数类型,足够保存两个迭代器之间的距离
//反向容器
reverse_iterator //按逆序寻址元素的迭代器.(++是往前的)
c.rbegin(), c.rend(); //尾元素和头元素之前位置的迭代器
3.迭代器转化
//非常量iterator可以转变为常量的iterator
list<string>::const_iterator it = a.begin(); //正确
4.容器构造函数
//迭代器初始化
C c(b,e); //b和e都是迭代器.初始化的就是迭代器的内容;
5. array
1.初始化
array<int,10> a; //a 是10个int型的数组(10个0)
array<string,10> a; //a 是10个string型的数组
array<int,10> a{0,1,2,3,4,5,6,7,8,9}; //array存储从0~9
array<int,10> a{1} //a[0] = 1,其它全0
2.可以拷贝
int digs[10] = {0,1,2,3,4,5,6,7,8,9};
int args[10] = digs; //错误,内置数组不可拷贝
array<int,10> digs{0,1,2,3,4,5,6,7,8,9};
array<int,10> args = digs; //正确,array可以拷贝赋值
3.(!!!primer错误!!!,现在已经可以)不能直接等于花括号序列
array<int,10> digs{0,1,2,3,4,5,6,7,8,9};
digs = {0,1}; //现在是正确的,因为array已经支持assign;
//digs = {0,1,0,0,0,0,0,0,0,0}
vector<int> t{ 1,2,3,4 };
t = { 0 }; //正确.因为可以用assign;
更新点:
6. assign
//assign是直接删除原来的内容,再重新赋值
list<string> names{"a","b","c","d"};
vector<const char*> oldstyle;
oldstyle = names; //错误,类型不匹配
vector<const char*> newstyle(names.begin(),names.end()); //正确
oldstyle.assign(names.begin(), names.end()); //正确,与上面等价
7. swap函数
swap需要注意不会去拷贝,复制数组中内容.只是交换了两个容器的内部数据结构.保证常数时间内完成
一般使用非成员函数的swap函数(算法库中)
8. 容器元素是拷贝来的
用一个对象初始化容器或者将一个对象插入到容器中,实际上放入到容器中的时对象值的一个拷贝
9. insert
insert(迭代器,个数,值); //迭代器位置插入多少个值
10.下标操作和at
区别:
- at操作安全,下标操作越界时会直接报错.at在越界时返回一个out_of_range异常;
- 下标操作会比较快,因为at需要判断是否异常!
11.删除
//删除迭代器所指向的内容,均返回删除后的第一个元素位置迭代器
c.earse(p); //p为迭代器
c.earse(b,e); //删除b,e迭代器范围内的元素,左闭右开
12. resize() 和 reserve()区别
//共同的,都可以用来增大或者缩小容器.array不支持
/*
区别:
1.resize()大小扩展到指定长度,然后在末尾补充0到添加的长度;如果容量太小也会进行扩充
2.reserve()容量扩展到指定长度,但是不会添加0;而且size大小不变.
删除:
1.resize()如果变小,那么会删除大于指定长度之外的元素
2.reserve()无法指定小于size(),即 容量 >= 大小是肯定的;
*/
vector<int> test{ 0,0,0,0,0,0,0 };
cout << test.size() << endl; 7
test.reserve(4);
cout << test.size() << endl; 7
test.resize(4);
cout << test.size() << endl; 4
//!记住,reverse不改变元素数量,但resize会!
//2.shrink_to_fit() 让 capacity = size.
13.迭代器失效
vector 和 string
- 容器重新分配空间,全部迭代器失效
- 容器插入一个元素,但是没有重新分配空间,那么就失效插入位置后的迭代器
list 和 forward_list
- 删除时除了直接指向的迭代器失效,其它均有效
deque
- 删除中间位置时,迭代器均失效.
- 删除头尾,其它迭代器有效
所以一般不要保存尾部迭代器.如果需要修改容器大小(插入,删除.resize),那么一定不要保存
14.vector的增长
如果resize 或 reserve时超出给定的 capacity.那么就会扩展,扩展的大小看具体实现(vs2017在第四次后时1.5倍速增长,gcc 5.4.0 2倍)
vector<int> a;
cout << a.capacity()<< endl; //0 最开始是0
int num = 0;
int n = 10;
int *p = NULL;
while (n--)
{
a.push_back(10);
cout << a.capacity()<< endl; //1 2 3 4 6 6 9 9 9 13
if (p != &a[0]) //前面线性增长,后面是1.5倍增长
{
p = &a[0];
num++;
}
}
cout << num << "次" << endl; //7次
15.特殊的string函数
//构造函数
//还可以接受const char*. 位置为指针 + 数字
string s1 = ".....";
string s2(s1,pos2); //s2字符串的值S1从下标pos2开始到结束
string s2(s1,pos2,len2) //s2是字符串s1从下标pos2开始截取len2长度的字符串
//插入和删除
s.insert(s.size(),5,'!'); //在末尾插入五个'!';
s.insert(s.size() - 5,5); //删除倒数5个字符;
//也可以接受const char*
const char*cp = "hello,world";
s.assign(cp,5); //hello
s.insert(s.size(),cp + 5); //在hello后面插入,world;
16. substr 字符串截取
//从字符串中截取index下标开始,长度为len的字符串返回!长度默认值为 s.size() - index;
string temp = s.substr(index,len);
17. replace 字符串替换
s.replace(11,3,"5th"); //从第十一位开始替换3个字符为5th
//其实等价于
s.earse(11,3);
s.insert(11,3,"5th");
18. 字符串查找
//大小写敏感,任何一个查找都可以指定第二个参数pos,表示从pos位置开始寻找
str.find("str"); //找到返回开始位置,没找到就返回npos(str.npos);
str.find_first_of(num); //查找在num字符串中任意一个字符第一次出现的下标;
str.find_last_of(num); //查找在num字符串中任意一个字符最后一个出现的下标;
str.find_first_not_of(num); //查找第一个没出现在num字符串中的字符
str.find_last_not_of(num); //查找最后一个没出现在num字符串中的字符
19.容器设配器
1.类型
- stack 栈
- queue 队列
- priority_queue 优先队列
2.实现
stack 可以用除了 forward_list 和 array外的其它容器来实现(需要back,push_back)
queue 可以用 list 和 deque 来实现(需要front,back,push_back,pop_back,push_front,pop_front)
priority_queue 可以 vector 和 deque来实现(需要 front,push_back和pop_back以及随机访问能力).
//一般情况下,stack 和 queue 基于 deque实现, 而priority_queue 基于 vector 实现;
//但是可以用顺序容器来修改默认值,比如指定用vector来实现stack
stack<int,vector<int>> stk; //指定用vector实现的stack
priority_queue<int, vector<int>, greater<int>> que; //小根堆,小的在上面
priority_queue<int, vector<int>, less<int>> que; //大根堆,大的在上面