STL容器中元素的删除erase()、remove()

来源:互联网 发布:cmd mac地址 编辑:程序博客网 时间:2024/05/22 05:02

1.引言

       以下代码有什么问题,如何修改?

[cpp] view plaincopy
  1. #include<iostream>  
  2. #include<vector>  
  3. using namespace std;  
  4.   
  5. void print(vector<int>);//传引用不妥!!  
  6.   
  7. int main()  
  8. {  
  9.     vector<int> array;   
  10.     array.push_back(1);  
  11.     array.push_back(6);  
  12.     array.push_back(6);  
  13.     array.push_back(3);  
  14. //删除array中的所有的6  
  15.     vector<int>::iterator itor;  
  16.     vector<int>::iterator itor2;  
  17.     itor=array.begin();  
  18.     for (itor=array.begin();itor!=array.end();itor++;)  
  19.     {  
  20.         if (6==*itor)  
  21.         {  
  22.             itor2=itor;  
  23.             array.erase(itor2);  
  24.         }  
  25.     }  
  26.     print(array);  
  27.     return 0;  
  28. }  
  29.   
  30. void print(vector<int> v)  
  31. {  
  32.     cout<<"\nvector size is: "<<v.size()<<endl;  
  33. }  


 

2.vector中erase源码

       这段代码运行后容量只减小1,具体问题出在哪不知道。先看一下erase的源码。

[cpp] view plaincopy
  1. iterator erase(iterator position)   
  2. {  
  3.     if (position + 1 != end()) //若position不是指向最后一个元素  
  4.            copy(position + 1, finish, position); //运用的是copy,将删除位置的元素向后移动  
  5.     --finish;//vector中finish所指位置为end()返回值   
  6.     destroy(finish);  
  7.     return position;  
  8. }  
  9. iterator erase(iterator first, iterator last) //允许last在first之前,后果自负  
  10. {  
  11.     iterator i = copy(last, finish, first);  
  12. destroy(i, finish);  
  13. finish = finish - (last - first);  
  14.     return first;  
  15. }  


 

       现在知道了,如果这时删除一个元素之后,itor已经指向下一个元素,所以再调用itor++,那么连续的26就只能删除前一个。

       所以以上的for循环可以改为:

[cpp] view plaincopy
  1. for (itor=array.begin();itor!=array.end();itor++;)  
  2. {  
  3.     if (6==*itor)  
  4.     {  
  5.         itor2=itor;  
  6.         array.erase(itor2);  
  7.         itor--;  
  8.     }  
  9. }  


 

3.remove源码

       但是这样的代码可读性欠佳,还有一种改法就是更加规范的简洁的操作:调用算法remove,之后再进行erase

       此时将for循环替代为:array.erase(remove(array.begin().array.end(),6),array.end());当然这个时候要包含头文件<algorithm>

      

       为什么要删除,remove返回后的迭代器到vector末尾的元素呢?看remove算法源码。

      

       remove操作移除[first,last)之中所有与value相等的元素。这一算法并不真正从容器中删除那些元素(换句话说容器的大小并没有改变),而是将每一个不与value相等的元素轮番赋值给first之后的空间。返回值ForwardIterator标示出重新整理后的最后元素的下一个位置。例如序列{0,1,0,2,0,3,0,4},如果执行remove删除0,则结果是{1,2,3,4,0,3,0,4},返回值ForwardIterator指向第5个元素。所以如果要删除那些残余元素可以使用erase的两迭代器版本。源码如下:

[cpp] view plaincopy
  1. tamplate<class ForwardIterator, class T>  
  2. ForwardIterator remove(ForwardIterator first, ForwardIterator last, const T& value)  
  3. {  
  4.     first=find(first, last, value);//找到第一个相等的元素  
  5.     ForwardIterator next = first;//以next标示出来  
  6.     //以下利用“remove_copy()允许新旧容器重叠”的性质,进行移除操作  
  7.     //并将结果置于原容器中  
  8.     return first == last ? first : remove_copy(++next,last,first,value);  
  9. }  


        remove_copy并不改变原来的容器,只是将所要删除的值删除后,将新容器存储在result迭代器所指的位置处。

[cpp] view plaincopy
  1. tamplate<class InputIterator, class OutputIterator, class T>  
  2. OutputIterator remove_copy(InputIterator first, InputIterator last, OutputIterator result, const T& value)  
  3. {  
  4.     for(;first != last;++first)  
  5.         if(*first != value)    //如果不相等  
  6.         {  
  7.             *result = *first;  //赋值给新容器  
  8.             ++result;                 
  9.         }  
  10.     return result;  
  11. }  


 

        当然remove函数也有仿函数版本的remove_ifremove_copy_if

4.list中的remove和erase操作

       list中的erase

[cpp] view plaincopy
  1. iterator erase(iterator position)  
  2. {  
  3.     link_type next_node = link_typr(position.node->next);  
  4.     link_type prev_node = link_typr(position.node->prev);  
  5.     prev_node->next = next_node;  
  6.     next_node->prev = prev_node;  
  7.     destroy_node(position.node);  
  8.     return iterator(next_node);  
  9. }  


 

        remove是算法库中的一个算法,但是list的结构使用这种remove算法时效率低下。根据list的结构,标准库专门为list设计了remove操作(其他容器是没有的)。

[cpp] view plaincopy
  1. template<class T, calss Alloc>  
  2. void list<T,Alloc>::remove(const T& value)  
  3. {  
  4.     iterator first = begin();  
  5.     iterator last = end();  
  6.     while(first != last)  
  7.     {  
  8.         iterator next = first;  
  9.         ++next;  
  10.         if(*first == value)
0 0