语言/CPP {迭代器iterator, `for(:)`方式遍历}

语言/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)这个操作;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值