STL迭代器
STL将容器(Containers)和算法(Algorithms)分隔开,两者之间的纽带就在于迭代器(Iterators)。
迭代器也是一种智能指针,重载了例如常见的operator*
以及operator->
。
迭代器有常见的五种相应型别:
iterator_category
value_type
difference_type
pointer
reference
假设迭代器有:ite,ite2
:
1. value_type
: 迭代器所指对象的类型,假设ite
是一个mutable iterator
,则*ite
返回的类型就是value_type
。
2. reference
:迭代器所指对象的引用类型,假设ite
是一个const iterator
,则*ite
返回的类型就是reference
。
2. difference_type
: 两个同类型迭代器之间的距离,例如ite-ite2
。
3. pointer
: operator->
返回的类型。
4. iterator_category
: 迭代器的分类。
iterator_category
有五种,分别是:
Input Iterator(输入迭代器)
Output Iterator(输出迭代器)
Forward Iterator(前向迭代器)
Bidirectional Iterator(双向迭代器)
Random Access Iterator(随机访问迭代器)
这五种迭代器的关系并不是完全的继承关系,而是继承中带丛属的关系:
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
输入/输出/前向迭代器支持的操作符重载有:
operator*,operator++,operator==,operator!=,operator->
双向迭代器在上述的基础上还支持:
operator--
随机访问迭代器在双向迭代器的基础上还支持:
operator<, operator[], operator+=, operator-=
各个容器的迭代器类型:
- vector<T>
:随机访问迭代器,本质是T*
,尤其要注意支持operator<
和operator[]
,因此经常可以看到这样访问vector:
vector<int> vec(10);
for(int i = 0; i < 10; ++i) {
vec[i] = 1; //vec[i] <==> *(vec.begin()+i)
}
for(auto ite = vec.begin(); ite < vec.end(); ++ite) {
*ite = 1; //ite < vec.end()通常也写成ite != vec.end()
}
deque<T>
:随机访问迭代器list<T>
:双向迭代器:不支持operator<, operator[]
,所以不要这样使用:
list<int> li(10);
for(int i = 0; i < 10; ++i) {
li[i] = 1; //wrong
}
for(auto ite = vec.begin(); ite < vec.end(); ++ite) {
*ite = 1; //ite < vec.end()必须写成ite != vec.end()
}
map/multimap/set/multiset
:底层的迭代器都是红黑树RBtree
的迭代器,也是双向迭代器:不支持operator<, operator[]
。hash_map/hash_set
:底层的迭代器都是hashtable
的迭代器,也就是前向迭代器,既不支持operator<, operator[]
,也不支持operator--
,所以不要这样做:
hash_set<int> hs;
//some init
...
for(auto ite = hs.end() - 1; ite != ite.begin(); --ite) {
... //这样做是不对的,迭代器必须从前往后遍历
}
stack/queue/priority_queue
:这些容器不提供迭代器,也不提供遍历功能。