语言/CPP {迭代器iterator, for(:)
方式遍历}
迭代器
定义
支持{++后移, *取值, !=判等价
}的自定义类;
int N = A.size();
double ANS = 1e10;
FOR_( i, 1, N/2){
auto it = std::min_element( A.begin(), A.end());
auto it_ma = std::max_element( A.begin(), A.end());
ANS = std::min( ANS, ((*it) + (*it_ma))/2.0);
A.erase( it);
A.erase( it_ma);
}
return ANS;
错误
#容器一旦修改, 所有迭代器都就失效了#
比如一个问题是 删除最小和最大元素, 如果你auto mi = std::min_element(...), ma = std::max_element(...)
, 直接A.erase( mi); A.erase( ma);
这是错误的, 因为当erase(mi)
后 ma
就失效了;
所以 正确做法是: 当你erase(mi)
之后, 通过A.erase( std::max_element(A.begin(), A.end())
来删除;
性質
迭代器 其实并不是看作是指针… 还不是很了解他 先说一些现象把;
比如对于容器 A,B
, 过去我以为A.end()
就类似于是nullptr
, 其实这是错误的, 因为A.end() != B.end()
;
.
这里举几个例子 现在还不是很懂, set<int> A,B
那么不管A,B
里面什么数据 一定有A.end() != B.end()
, 但对于vector<int> A,B
居然会有A.end()==B.end()
但一旦你修改他 比如A和B 同时resize(1)
那么一定有A.end() != B.end()
, vector
很特别 比如A.end() == vector<int>::iterator()
但其他容器不是这样的; 个人认为 这只是个极小概率事件… 你可以认为不同的对象之间 他们的end()
迭代器 是不同的, 即绝大多情况下 都会有A.end() != B.end()
;
但是, 这个A.end()
一旦对象A
构造出来了 那么他的值就不变了(这里的不变 是指迭代器的同一性比较) 不管你怎么增删修改这个容器, 你修改这个容器 其他的迭代器(即除了end()
之外的 比如begin(), begin()+1, ...
) 他们是会改变的 (因为容器涉及到动态内存 你内存改变了 迭代器肯定变了) 但只有end()
迭代器是不变的;
这A.end()
他虽然是不变的, 但是 他不等于默认迭代器, 也就是 set<int> A;
此时A.end() != set<int>::iterator()
;
当容器为空时 此时会有A.begin() == A.end()
, 因为A.end()
是恒定不变的 这也说明 A.begin()
是会随着容器改变的;
@DELI;
迭代器 虽然形象化下他就是指針, 但是 因为他是个类 默认是不支持cout
的, 所以你cout
或者 (void *)
強轉, 都是不可行的;
此時你可以 &(*s.begin())
來輸出元素的地址, 而不是cout<< s.begin()
;
for(:)
方式遍历
定义
for( auto i : A)
的本质是: for( auto j = A.begin(); j != A.end(); j++){ auto i = *j;}
;
性质
#自定义类实现for循环#
对于ST obj;
你要想实现for( auto i : obj)
这个操作, 那么就必须如下:
class ST{
public:
class It{
public:
int i = 0;
void operator++(){ ++i;}
string operator*()const{
return to_string(i);
}
bool operator!=( const It & it) const{
return i != it.i;
}
};
It begin(){ return {0};}
It end(){ return {6};}
};
即你的自定义类 必须支持begin(), end()
两个函数; 然后他的返回值类型 即It
, 她不一定是自定义类型, 只要他支持{++后移, *取值, !=判等价
}即可; (比如It == int*
指针是系统类型 不是我们的自定义类型, 但是因为指针本身就支持 这3个操作 所以是可以的);
@DELI;
for( T i : A)
他的本质 就是调用了A.begin(), A.end()
两个成员函数, 因此 你的自定义类 只要支持这两个函数 _T * begin(){ return Arr;}
和 _T * end(){ return Arr + Size;}
, 那么他也可以进行for( auto i : obj)
这个操作;