首页 > 代码库 > STL中慎重选择删除元素的方法
STL中慎重选择删除元素的方法
一、要删除容器中有特定值的所有对象
1、如果容器是vector、string或deque,则使用erase-remove习惯用法。例如:
vector<int> c;
c.erase(remove(c.begin(),c.end(),1963),c.end());//删除值是1963的元素
下面讲一下算法remove:
template<classForwardIterator,class T>
ForwardIteratorremove(ForwardIterator first,ForwardIterator last,const T& value)
{
first = find(first,last,value);
ForwardIterator next = first;
return first ==last?first:remove_copy(++next,last,first,value);
}
template<classInputIterator,class OutputIterator,class T>
OutputIteratorremove_copy(InputIterator first,InputIterator last,OutputIterator result,constT& value)
{
for(;first != last;++first)
if (*first != value)
{
*result = *first;
++result;
}
return result;
}
移除[first,last)之中所有与value相等的元素。这一算法并不真正从容器中删除那些元素(换句话说容器大小并为改变),而是将每一个不与value相等(也就是我们并不打算移除)的元素轮番赋值给first之后的空间。返回值标示出重新整理后的最后元素的下一位置。例如序列{0,1,0,2,0,3,0,4},如果我们执行remove(),希望移除所有0值元素,执行结果将是{1,2,3,4,0,3,0,4}。每一个与0不相等的元素,1,2,3,4,分别被拷贝到第一、二、三、四个位置上。第四个位置以后不动,换句话说是第四个位置之后是这一算法留下的残余数据。返回值ForwardIterator指向第五个位置。如果要删除那些残余数据,可将返回的迭代器交给区间所在之容器的erase()成员函数。注意,array不适合使用remove()和remove_if(),因为array无法缩小尺寸,导致残余数据永远存在。对array而言,较受欢迎的算法是remove_copy()和remove_copy_if()。
remove_copy移除[first,last)区间内所有与value相等的元素。它并不真正从容器中删除那些元素,而是将结果复制到一个以result标示起始位置的容器身上。新容器可以和原容器重叠,但如果对新容器实际给值时,超越了旧容器的大小,会产生无法预期的结果。返回值OutputIterator指出被复制的最后元素的下一位置。
2、如果容器是list,则使用list::remove。例如:
list<int> c;
c.remove(1963);//该成员函数无返回值
3、如果容器是一个标准关联容器,则使用它的erase成员函数。例如:
map<int,int>c;
c.erase(1963);//删除键值是1963的元素
对于标准关联容器使用任何名为remove的操作都是完全错误的。这样的容器没有名为remove的成员函数,使用remove算法可能会覆盖容器的值,同时可能会破坏容器。
二、要删除容器中满足特定判别式(条件)的所有对象
1、如果容器是vector、string或deque,则使用erase-remove_if习惯用法。例如我们不再从c中删除所有等于特定值的元素,而是删除使下面的判别式返回true的每一个对象:
bool badvalue(int);
c.erase(remove_if(c.begin(),c.end(),badvalue),c.end());
2、对于list,则使用list::remove_if。例如:
c.remove_if(badvalue);
3、如果容器是一个标准关联容器,则使用remove_copy_if和swap,或者写一个循环来遍历容器中的元素,记住当把迭代器传给erase时,要对它进行后缀递增。例如:
AssocContainer<int>c;
…
AssocContainer<int>goodvalues;
Remove_copy_if(c.begin(),c.end(),inserter(goodvalues,goodvalues.end()),badvalue);
c.swap(goodvalues);
或者
AssocContainer<int>c;
…
for(AssocContainer<int>::iteratori = c.begin();i != c.end();)
{
if(badvalue(*i))
c.erase(i++);
else
++i;
}
三、要在循环内部做某些(除了删除对象之外的)操作:
1、如果容器是一个标准序列容器,则写一个循环来遍历容器中的元素,记住每次调用erase时,要用它的返回值更新迭代器。例如:
ofstream logFile;
SeqContainer<int>c;
for (SeqContainer<int>::iteratori = c.begin();i != c.end();)
{
if (badvalue(*i))
{
logFile << “Erasing” << *i<< ‘\n’;
i = c.erase(i);//把erase的返回值赋给i,使i的值保持有效
}
else
{
++i;
}
}
2、如果容器是一个标准关联容器,则写一个循环来遍历容器中的元素,记住当把迭代器传给erase时,要对迭代器做后缀递增。例如:
ofstream logFile;
AssocContainer<int>c;
…
for(AssocContainer<int>::iterator i = c.begin();i != c.end();)
{
if (badvalue(*i))
{
logFile<< “Erasing ” << *i << ‘\n’;
c.erase(i++);
}
else
++i;
}