算法和迭代器
原文链接:https://blog.csdn.net/weixin_45389639/article/details/121618243
算法的一般结构
algorithm看不见container,所以它所需要的一切信息都必须从iterator获取,而iterator(由container提供)必须要回答algorithm的所有提问container才能搭配该algorithm的所有操作。
- STL源码中所有算法都遵循以下格式:
template<typename iterator>
Algorithm(iterator itr1,iterator itr2){
...
}
template<typename iterator,typename Cmp>
Algorithm(iterator itr1,iterator itr2,Cmp comp){
...
}
迭代器分类
迭代器的关联类型iterator_category表示迭代器类型,其分类为以下5种:
1. struct input_iterator_tag{};
2. struct ouput_iterator_tag{};
3. struct forward_iterator_tag:public input_iterator_tag{};
4. struct bidirectional_iterator_tag:public forward_iterator_tag{};
5. struct random_access_iterator_tag:public bidrectional_iterator_tag{};
采用class而非enum来表示迭代器类型,出于以下两个考量:
使用类继承可以表示不同迭代器类型的从属关系。
STL算法可以根据传入的迭代器类型调用不同版本的重载函数。
void _displayIteratorCategory(random_access_iterator_tag) {
cout << "random_access_iterator_tag" << endl;
}
void _displayIteratorCategory(forward_iterator_tag) {
cout << "forward_iterator_tag" << endl;
}
void _displayIteratorCategory(bidirectional_iterator_tag) {
cout << "bidirectional_iterator_tag" << endl;
}
void _displayIteratorCategory(input_iterator_tag) {
cout << "input_iterator_tag" << endl;
}
void _displayIteratorCategory(output_iterator_tag) {
cout << "output_iterator_tag" << endl;
}
template<typename T>
void displayIteratorCategory(T iter) {
typename iterator_traits<T>::iterator_category cag;
_displayIteratorCategory(cag);
}
void iteratorCategoryTest() {
displayIteratorCategory(vector<int>::iterator()); //random_access_iterator
displayIteratorCategory(array<int,10>::iterator()); //random_access_iterator
displayIteratorCategory(list<int>::iterator()); //bidirectional_iterator
displayIteratorCategory(forward_list<int>::iterator()); //forward_iterator
displayIteratorCategory(deque<int>::iterator()); //random_access_iterator
displayIteratorCategory(set<int>::iterator()); //bidirectional_iterator
displayIteratorCategory(map<int,int>::iterator()); //bidirectional_iterator
displayIteratorCategory(unordered_set<int>::iterator()); //forward_iterator
displayIteratorCategory(unordered_map<int,int>::iterator()); //forward_iterator
displayIteratorCategory(istream_iterator<int>()); //input_iterator
displayIteratorCategory(ostream_iterator<int>(cout,"")); //output_iterator
}
- 容器vector、array、deque对使用者来说空间是连续、可跳跃的,所以迭代器是random_access_iterator。
- 容器list为双向链表,set、map、multimap、multiset本身是有序的,支持双向移动,所以为bidirectional_iterator。
- 容器forward_list为单向链表容器unordered_set、unordered_map、unordered_multiset、unordered_map哈希表中的每个桶都是单向链表.因此其迭代器只能单向移动,因此是forward_iterator类型。
- 迭代器istream_iterator和ostream_iterator本质上是迭代器,后文会提到这两个类的源码。
迭代器对算法的影响
STL中大部分算法会根据传入的迭代器类型以及其他信息来调用不同的重载函数,针对特定的迭代器调用最优的重载版本。
STL中distance根据不同iterator_category执行不同的重载函数
template<class InputIterator>
inline iterator_traits<InputIterator>::difference_type
_distance(InputIterator first,InputIterator last,input_iterator_tag){
iterator_traits<InputIterator>::difference_type n=0;
while(first!=last){
++first;
++n;
}
return n;
}
template<class RandomAccessIterator>
inline iterator_traits<RandomAccessIterator>::difference_type
_distance(RandomAccessIterator first,RandomAccessIterator last,random_access_iterator_tag){
return last-first;}
//这里的iterator_traits<InputIterator>::difference_type 为函数的返回类型,只有在运行的时候才确定是何种类型
template<class InputIterator>
inline iterator_traits<InputIterator>::difference_type
distance(InputIterator first,InputIterator last){
iterator_traits<InputIterator>::iterator_category category;
}
STL中Advance根据不同iterator_category执行不同的重载函数
templaye<class BidirectionalIterator,class Distance>
inline void _advance(BidirectionalIterator&i,Distance n,bidirectional_iterator_tag){
if(n>=0){
while(n--)
++i;
}
else{
while(n++)
--i;
}
}
templaye<class RandomAccessIterator,class Distance>
inline void _advance(RandomAccessIterator&i,Distance n,random_access_iterator_tag){
i+=n;
}
template<class InputIterator,class Distance>
inline void advance(InputIterator& i,Distance n){
_advance(i,n,iterator_category(i));
}
template<class Iterator>
inline typename iterator_traits<Iterator>::iterator_category
iterator_category(const Iterator&){
typedef typename iterator_traits<Iterator>::iterator_category category;
return category(); //创建temp category object
}
STL中copy根据不同iterator_category和type traits执行不同的重载函数
STL中destroy根据不同iterator_category和type traits执行不同的重载函数
STL算法都是模板函数,无法对传入的iterator_category类型做出限定,但源码中的模板参数名还是对接收的iterator_category做出了一定的暗示。例如在命名模板参数上。
template<class InputIterator>
inline Iterator_traits<InputIterator>::diffrence_type
distance(InputIterator first,InputIterator last){
...
}
template<class ForwardIterator>
inline void rotate(ForwardIterator first,ForwardIterator middle,ForwardIterator last){
...
}
template<class RandomAccessIterator>
inline void sort(RandomAccessIterator first,RandomAccessIterator last){
...
}
template<class InputIterator,class T>
InputIterator find(InputIterator first,InputIterator last,const T&value){
...
}