迭代器:Primer c++ 阅读记录
除了vector之外,标准库还定义了其他几种容器,而所有的标准库容器都可以使用迭代器。只有少数容器可以支持下标运算符,所以使用迭代器会更加的通用。strting对象严格来说并不属于容器的类型,但它支持很多与容器类型类似的操作,比如支持迭代器的使用。
迭代器也提供了对对象的间接访问,其对象是容器中的元素,与指针有些相似。迭代器并不是一个整体的概念,容器中每一个元素都可以对应一个迭代器,或是定义了一个迭代器,通过移动迭代器来实现遍历所有的元素。
迭代器的使用
有迭代器的类型同时拥有返回迭代器的成员函数。比如begin和end;
auto b = v.begin(); e = v.end(); 由编译器来决定b、e的类型,这里的返回值类型都是迭代器,而不是元素。
begin:返回指向,第一个元素(或是第一个字符)的迭代器;
end:负责返回尾后迭代器,这个迭代器没有实际意义,仅作数据处理使用。
c++11之中新引入了如下函数
cbegin和cend
使用方式类似于begin和end,只不过返回值类型都是const_iterator;可以避免值的改变
迭代器运算符
*iter 返回迭代器所指向元素的引用(与指针不同i);
iter->men等价于(*iter).men 解引用iter并获取men成员(这里可以看出并非地址);
++iter 指向容器中的下一个元素;
--iter 指向容器中的上一个元素;
==或!= 判断迭代器所指元素是否相等,或者是否指向同一个容器的尾后迭代器;
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> number = {1,3,5,7,9,12};
for(auto this1 = number.begin(); this1!=number.end();)
{
*this1+=3; //给每个数字都加上3
cout<<*this1<<endl;
this1++;
}
return 0;
}
使用迭代器访问其中的元素并进行运算,有点相似于指针。
迭代器的类型:iterator和const_iterator
其实无须知道迭代器的准确类型,标准库类型使用iterator和const_iteartor来表示迭代器的类型;
vector<double>::iterator d1; d1能够读写迭代器vector<double>中的元素;
vector<double>::const_iterator d2; d2只能够读取迭代器vector<double>中的与元素,如果vector中的对象是const double,那么对应的只能是const_iterator这点和常量指针相似,以元素本身为核心,指针、迭代器只是另外的访问途径;
解引用和成员访问相结合
解引用得到的对象,如果是类的对象,就有可能通过对象来访问其中的数据成员,或是调用成员函数。
例如:对于一个字符串组成的vector对象,可以定义it为该对象的迭代器
调用函数 (*it).empty(),来检查迭代器所指的字符串是否为空,注意是迭代器对应的对象来调用,而不是迭代器本身。
为简化以上,c++中定义了->运算符,结合了解引用运算符和成员访问运算符。
上述调用可以改为 it->empty(),在指针之中也有类似的操作。
迭代器运算:string和vector的迭代器提供了更多的运算符。
iter+(-)n 可以是迭代器一次移动若干个单位(到了尾部是否会固定?)。
iter+(-)= n 相当于iter=iter+(-)n,将+n后的结果赋给iter(迭代器之间的赋值)。
iter1 - iter2 得到迭代器位置之间的距离,但参与运算的两个迭代器必须指向同一个容器中的元素或尾端。
>、>+、<、<=、 迭代器位置之间的判断
迭代器运算:二分搜索
前提条件:容器中的数据是有序的
auto beg = text.cbegin(), end = text.cend(); 确定了搜索的范围,无须改变数据大小
auto mid = text.cbegin()+(end-beg)/2; 中间点,比较粗略的中间点。是迭代器之间的运算
while(mid!=end&&*mid!=target)
{
if(target<*mid) 确定目标的位置,在前半区还是后半区
end = mid ; 忽略后半部分
else
beg = mid+1 前面已经确定了中间点不是target
mid = beg+(end-beg)/2
}
注意事项:
1.end()成员的使用,指向尾迭代器的对象没有意义,对它解引用操作是违法的。
2.迭代器中大多没有关于<运算符,所以在上述for循环中使用了!=号,这个可以通用。
3.但凡是使用了迭代器的循环体(范围for循环等),都不要向迭代器所属的容器中添加元素。否则可能造成迭代器失效。
4.编译器要支持c++11,不然无法识别一些符号。