"C++ Primer" 读书笔记 第十一章 泛型算法
首先我们注意一下第十章 关联容器中有哪些需要注意的:
- 顺序容器是通过元素在容器中的位置访问的,而关联容器则是通过元素的键 (key)进行访问的
- pair类型是一种模板类型,类型形参为数据成员的类型
- map容器的每一个键值对是一个pair类型。pair类型是一种标准库类型,但是其成员first和second却是public的
- 关联容器没有pop/push等操作,也无法通过vector<char>('a',5);这种方式定义
- 键的类型必须定义 < 操作符,默认情况下将作为比较函数。这个比较函数必须在键类型上支持严格弱排序
- 因此不支持 < 操作符的类型将不能作为 键
- 对map的迭代器进行解引用将得到键值对,是一个pair类型的对象;而下标返回的是mapped_type, 值的类型
- 用下标访问map中不存在的元素将自动地添加一个新的元素,且值被初始化为默认值(int就初始化为0)
- count函数检测是否存在某个键;find函数返回指向目标键的迭代器,如果元素不存在,则返回end
- earse函数实现删除元素,可以取 键(返回删除的元素个数 0或1);可以取迭代器或迭代器范围(返回void)
泛型算法
泛型算法可以作用在不同类型的容器和不同类型的元素上。当然也可以作用在内置数组类型上。
标准容器定义的操作其实很少,主要是:元素的添加和删除、访问首尾元素、获取容器的大小、获取begin()和end()迭代器。
一般使用算法都要给定迭代器范围。算法不依赖容器的操作,而完全通过迭代器解决四个问题:
1. 遍历集合的方式:通过迭代器自增实现遍历容器中所有元素
2. 算法应用的范围在何处终止:通过超出末端一位的哨兵迭代器
3. 是否找到某个元素或是否通过算法达成某种效果:通过是否到达end体现
4. 元素间如何进行比较,== 操作符 < 操作符等,或者自行定义的比较函数
- 算法不会改变容器的大小:实际上算法不会插入或者删除元素,而是改变元素值或者移动位置
- 利用accumulate函数可以方便地将vector中所有的string连接为大的string,accumulate函数的第三个参数是必须的,作为起始值的同时也指定了以何种方式对迭代器解引用的值进行解释!
- 累加和的类型与起始值的类型相同,因此string类型相加不能用字符串字面值const * char作为起始值
- 泛型算法使得操作时类型是否匹配没那么重要:list<string>与vector<const *char>可以用find_first_of函数,因为string与char间定义了==操作符
- 向容器中写入元素的算法
- fill(v.begin(),v.end(),0)函数, 迭代器范围有效则写入,如果超出则终止,因此安全
- fill_n函数不会检查是否有效,这种写法不安全,因为容器本来就没有那么多空间存储新元素
- back_inserter是迭代器适配器,确保容器有足够的空间存储输出数据
- copy函数实现元素拷贝
- replace函数实现查找替换:replace(li.begin(), li.end(), 0, 42)
- replace_copy函数实现查找替换并拷贝到另一个容器 replace_copy(li.begin(),li.end(),back_inserter(ivec),0,42)
- 对容器元素重新排序的算法
- 去除重复:先调用sort进行排序,再调用unique函数实现重排序,返回一个迭代器,标记没有重复值的范围的下一个位置,再调用erase函数(注意增删容器元素要用到容器的方法)实现删除后面重复的元素
- 查找算法 均可以在最后加func判断函数,实现自定义“相等”
- find(beg,end,val)和count(beg,end,val)要求容器中的元素类型重载==操作
- find_if(b,e,func)返回迭代器范围中使func为true的第一个迭代器位置, count_if(b,e,func)则返回数量
- find_first_of(b1,e1,b2,e2)返回一个第一段迭代器范围中的某个位置,只要该位置的值在范围二中即可
- find_first_of(b1,e1,b2,e2,func)不用==操作,而用我们自己定义的判断函数来定义两个元素是否相等
- find_end(b1,e1,b2,e2)查找第二段范围内的元素在第一段范围内的最后一次出现
- adjacent_find(b,e,func)查找第一对相邻且使func()函数返回true的元素,默认==
- search(b1,e1,b2,e2)查找第二个子序列在第一个子序列出现的第一个位置
- search_n(b,e,count,val)查找指定的连续count个val的出现位置
- 迭代器,反向迭代器与distance()函数
// 使用distance()函数需要#include<iterator> string a = "hello world"; auto it1 = find(a.begin(),a.end(),'e'); distance(a.begin(), it1); // 得到1 auto it2 = find(a.rbegin(),a.rend(),'l'); distance(it2,a.rbegin());// 得到-1 distance(a.rbegin(),it2); // 得到1 // 注意反向迭代器以a.rbegin()为第一个位置;且反向迭代器用自增操作符++实际上是往左边移动了
注意反向迭代器与迭代器不能同时在一个算法中使用;
使用前向迭代器写元素的算法(只能用前向迭代器):
swap(e1, e2), iter_swap(it1, it2), fill(b, e, val), generate(b, e, Gen_func), replace(b, e, old_val, new_val), replace_if(b,e,func,new_val)