C++标准库的算法,是什么东西?
从语言层面上讲:
- 容器Container是个class template
- 算法Algorithm是个function template
- 迭代器Iterator是个class template
- 仿函数Functor是个class template
- 适配器Adapter是个class template
- 分配器Allocator是个class template
算法看不见容器,对其一无所知;所以,它所需要的一切信息都必须从Iterators取得,而Iterators(由容器提供)必须能够回答Algorithm的所有提问,才能搭配该Algorithm的所有操作。
迭代器的分类
不连续空间的容器迭代器都是不能跳的,比如List的迭代器是bidirectional_iterator_tag,Forward_LIst的迭代器是Forward_iterator_tag。
输入迭代器、输出迭代器、正向迭代器、双向迭代器、随机访问迭代器(描述了移动方式)
由每种容器的内存分布特性可推断其迭代器类型:
Array Vector Deque: 随机访问迭代器。
List Set Map(rb_tree):双向迭代器(红黑树节点之间是双向链接)。
Forward List:正向迭代器。
Unordered Set Map:由其底部实现的哈希表中的链表决定,可能为正向或者双向迭代器。
不同类型的迭代器是不同的类,上例可以通过函数重载写成不同的函数(_display_category())。
array<int,10>::iterator(),这里的前面是一个类型,类型+()是代表产生一个临时对象的意思。
不同版本标准库中的istream_iterator的iterator_category接口一样。对于自己迭代器的定义式input_iterator_tag/output_iterator_tag。
父类只是一些typedef,没有data,没有function,继承只是为了拥有这些typedef。
1.迭代器对算法的影响
之所以不用类型12345来区分,而是用对象的方式,一是_display_category调用时可以直接重载,而若是类型12345,则无法做到这样(这个原因略牵强);二是在算法实现时可以用上多态特性,而不必为每个类型写一个函数。
distance算法
distance用来知道两个指针间的距离。
distance函数时一般由其他算法调用的,而不是用户调用。
返回类型是traits中的difference_type(5个相关类型)而不是int之类的类型。
这种由一个主函数调用不同情况下的 iterator 重载次函数的形式,广泛存在与 STL 算法中。
因为 iterator_tag 是具有继承关系的类,所以所有的类型情况都可以 只提供几种方案并利用多态来实现。
advance算法
advance 函数为 iterator 向前操作,参数为 iterator 引用,分3种情况利用多态实现了所有迭代器类型的操作。
Copy算法
传递的三个参数:来源端的起止点和目的端的起点。
不断的检查,根据不同类型进行不同的处理。
- 一般 iterator 时,每复制过一个元素都要检查是否到头,效率较低。
- random_acess_iterator 时,根据黄字,可直接判断循环次数,效率较高。(随机访问表示连续内存分布)。
- trival op = 与 non_trival op= 如何判断:例如,复数类,只有两个元素 im 和 re ,没有指针,这样的类不需要写析构、拷贝构造、拷贝赋值函数,编译器默认生成的这些函数就是 non_trival 的。(第四讲 STL 之外,标准库之内的东西,比如traits)
input_iterator和output_iterator的不同
这就是容器的迭代器为什么要回答5个问题,根据不同类型做出不同的处理。
调用第一行编译是会通过的,因为它毕竟是个模板,需要接受所有的类型(继承类型),然而当到跳的那一步是还是会失败。
算法中的源码剖析
形如以下形式的接口才是C++标准库的算法:
template<typename Iterator>
std::Algorithm(Iterator itr1,Iterator itr2,...)
{
....
}
accumulate
accumlate 算法有两种重载的形式默认为累加,其中第二种接收一个自定义操作对数据做累计。
myobj() 表示函数对象(或称仿函数),实质是一个类或者结构体,重载了 operator() 。
for(decl:coll){ //decl是变量声明,coll是一堆东西
statement
}
算法replace,replace_if,replace_copy 命名带if的会带一个条件。
这8个就是关联性容器,可以由key找到value,因此它们有自己比较快的算法。(没有sort是因为存完后就排序好了)
标准库中的sort是需要迭代器可以随便跳的,所以List和forward_list是不可以用的。
rbegin() 通过 适配器reverse iterator 调整 end() 得到。
算法binary_search
必须是一个排序序列才可以使用binary_search。