(前置技能)关于++i和i++
i++的过程:先拷贝一份原始值至另外的内存地址中,然后这份被拷贝的原始值应用于后续的计算过程中,然后自身加1;
++i的过程:先自增,然后把自增后的值拷贝一份到另外的内存地址中,这份被拷贝的值应用于后续计算。
内建数据类型的情况,效率没有区别。
自定义数据类型的情况,++i效率较高。
erase方法可以返回下一个有效的iterator
set,map的迭代器失效
typedef map<int, int> Map;
typedef map<int, int>::iterator MapIt;
Map m;
MapIt it;
for(it = m.begin(); it != m.end(); /*不能再自增了,不能i++*/){ //因为对于关联的容器map来说, m.erase(it);后,it就失效了
if(*it%2 == 0)
m.erase(it++);//这个原理看上面i++
else
it++;
//正解
if(*it%2 == 0)
it = m.erase(it);//通过erase方法的返回值来获取下一个有效迭代器
else
it++;
}
vector,deque的迭代器失效
//序列式容器,使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。
vector<int> v;
for(vector<int>::iterator it = v.begin(); it != v.end(); /*不能再自增了*/){
it = v.erase(it); // 删除当前的iterator,后面的vector元素自动向前挪动,后面的迭代器全部会失效(关联的map容器元素不会自动挪动), 所以不能再把it进行++
}
触发各容器迭代器失效的情况
list
内部数据结构:双向环状链表。
使用了不连续分配的内存,它的erase方法也会返回下一个有效的iterator,因此上面两种迭代方法都可以使用。
增加任何元素都不会使迭代器失效。删除元素时,除了指向当前被删除元素的迭代器外,其它迭代器都不会失效。
vector
内部数据结构:数组。
vector的迭代器在内存重新分配时将失效 或
指向当前元素以后的任何元素的迭代器都将失效。
(重新分配内存并添加元素 和 删除或者添加但不重新分配 分别对应这两种情况)
当删除元素时,指向被删除元素以后的任何元素的迭代器都将失效。
(因为数据结构是数组,明显知道删除后会使后面所有元素改变,所以删除O(n)也可以证明)
stack, queue
一般使用deque作为支持的序列容器。
不能遍历。。
map, set
关联式容器:使用了红黑树来实现,插入、删除一个结点不会对其他结点造成影响。
如果迭代器所指向的元素被删除,则该迭代器失效。
deque
增加任何元素都将使deque的迭代器失效。在deque的中间删除元素将使迭代器失效。在deque的头或尾删除元素时,只有指向该元素的迭代器失效。