开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情
迭代器
string
访问字符,vector
访问元素可以用下标,但是还有其他的容器却不一定支持,但是都会支持使用迭代器访问元素
迭代器提供了对象的间接访问,也从一个元素移动到下一个元素
使用begin()
和end()
获取迭代器;迭代器的类型由容器类型决定,一般都是T::iterator
类型,方便起见,直接使用auto
类型更为简单
auto b = v.begin(); //获取指向容器第一个元素的迭代器
auto e = v.end(); //获取指向容器尾元素的下一位的迭代器
注意end()
,叫尾后迭代器。返回的是尾元素的下一位置的迭代器,该迭代器指示的容器一个本不存在的尾后元素,表示已经处理完毕所有的元素;
迭代器类型
-
迭代器的准确类型一般可以不用知道,使用
iterator
或者const_iterator
表示迭代器的类型-
可以使用
iterator
迭代器访问并修改元素vector<int>::iterator it; //能读写vecotr<int>的元素 string::iterator it2; //能读写string的元素
-
const_iterator
和常量指针类似,只能读取不能修改元素vector<int>::const_iterator it; //只能读取vecotr<int>的元素 string::const_iterator it2; //只能读取string的元素
-
-
begin()
和end()
返回是否是const
迭代器由对象是否是常量决定如果对象是
const
的,那么迭代器就是const_iterator
;否者就是iterator
如果要明确的使用
const_iterator
,那么可以使用cbegin()
和cend()
访问元素的方法
和指针类似,可以使用*
解引用 也可以使用->
直接访问元素的方法
(it).empty(); //注意括号不能少,因为的优先级比.调用要低
it->empty(); //这个形式意思就是直接访问it指向的元素的empty方法
迭代器运算符
比较两个迭代器
如果两个迭代器指向的元素相同 或者都是同一个容器的尾后迭代器,则相等
访问元素
string s(""hello world");
//确保迭代器合法
if (s.begin() != s.end()) {
//获取迭代器
auto it = s.begin();
//访问元素
it = toupper(it);
}
通过解引用迭代器来获取它指向的元素
执行解引用的迭代器必须合法并确实指示着某个元素
试图解引用一个非法迭代器或者尾后迭代器是未定义的行为
迭代器移动
-
使用++或者--,这样迭代器就可以访问上一个或者下一个
//使用迭代器遍历vector //从首元素迭代器一直自增到尾后迭代器,使用++访问下一个元素 for(auto it = v.begin(); it!=v.end(); ++it) { cout << *it <<endl; }
-
并不是所有容器都有下标访问方法,所以养成习惯使用迭代器访问元素,就不需要太在意使用的是哪一种容器了,在泛型编程中特别实用
-
注意,和for类似,在使用迭代器访问容器元素的时候,也不能修改容器的大小(即增删元素)
迭代器运算
-
迭代器除了自增,自减之外,还能做数值的加减法
iter + n ; //表示迭代器位置向后移动n位 iter - n ; //表示迭代器位置向前移动n位
-
迭代器之间还能做减法,返回的是两个迭代器之间的距离
auto n = iter1 - iter2;
这个返回的类型是
difference_type
,是带符号的整数 -
使用关系运算符也可以做比较
返回的就是两个迭代器指向元素的前后顺序
例子
使用迭代器完成二分查找
vector<string>::iterator binarySearch(vector<string> v, const string &target)
{
auto begin = v.begin();
auto end = v.end();
//中间点
auto mid = begin + (end - begin) / 2;
//还有元素,且还没有找到目标
while (mid != end && *mid != target)
{
//目标在前半部分
if (target < *mid)
{
//右边区间收缩
end = mid;
}
//目标在后半部分
else
{
//左边区间后移
begin = mid + 1;
}
//新的中间点
mid = begin + (end - begin) / 2;
}
}