STL进阶--删除元素

Posted logchen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STL进阶--删除元素相关的知识,希望对你有一定的参考价值。

删除元素

从vector或deque删除元素

  vector<int> vec = {1, 4, 1, 1, 1, 12, 18, 16}; // 删除所有的1
  for (vector<int>::iterator itr = vec.begin(); itr != vec.end(); ++itr) {
     if ( *itr == 1 ) {
        vec.erase(itr);    //你或许会想到使用erase成员函数
     }
  }   // 的确,是可以达到目的 vec: { 4, 12, 18, 16}
  // 但是复杂度是: O(n*m),每删除一个元素,后面的往前移动

  // 如果使用算法remove
  remove(vec.begin(), vec.end(), 1);  // 复杂度 O(n) 
                                      // vec: {4, 12, 18, 16, ?, ?, ?, ?}

  
  
  vector<int>::iterator newEnd = remove(vec.begin(), vec.end(), 1);   // 将不删除的元素移到前面,O(n)
  vec.erase(newEnd, vec.end());  //删除最后无用的元素

  // 算法remove_if()和unique()也是类似


  // 此时vec仍然占了8个int空间: vec.capacity() == 8
  vec.shrink_to_fit();   // C++ 11
  // 现在vec.capacity() == 4 

  // For C++ 03:
  vector<int>(vec).swap(vec); // 相同效果,释放空的内存

从List删除

  list<int> mylist = {1, 4, 1, 1, 1, 12, 18, 16};

  list<int>::iterator newEnd = remove(mylist.begin(), mylist.end(), 1);  // 使用算法remove,O(n)
  mylist.erase(newEnd, mylist.end());


  mylist.remove(1);  // 成员函数更快,直接操作指针,从链上删除

从关联容器或无序容器中删除

  multiset<int> myset = {1, 4, 1, 1, 1, 12, 18, 16};

  multiset<int>::iterator newEnd = remove(myset.begin(), myset.end(), 1);  // O(n)
  myset.erase(newEnd, myset.end()); 

  myset.erase(1); // O(log(n)) or O(1)

结论

  • vector或者deque: 算法remove() + erase()
  • list:成员函数remove()
  • 关联容器或者无序容器:成员函数erase()

删除元素之后

// 看个关联容器的例子,此程序会发生什么
multiset<int> s = {1, 4, 1, 1, 1, 12, 18, 16};;

multiset<int>::iterator itr;
for (itr=s.begin(); itr!=s.end(); itr++) {
   if (*itr == 1) {
      s.erase(itr);      
      cout << "Erase one item of " << *itr << endl;
   } 
}

// 删除第一个元素成功,后面未定义的行为

解决方法:

multiset<int>::iterator itr;
for (itr=s.begin(); itr!=s.end(); ) {
   if (*itr == 1) {
      cout << "Erase one item of " << *itr << endl;
      s.erase(itr++);    //在删除之前,迭代器已经指向下一个
   } else {
      itr++;
   }
}

对于序列容器

vector<int> v = {1, 4, 1, 1, 1, 12, 18, 16};
vector<int>::iterator itr2;
for (itr2=v.begin(); itr2!=v.end(); ) {
   if (*itr2 == 1) {
      cout << "Erase one item of " << *itr2 << endl;
      v.erase(itr2++);    //这样仍然不安全,删除的元素后面的所有迭代器都失效
   } else {
      itr2++;
   }
}

解决方法:

for (itr2=v.begin(); itr2!=v.end(); ) {
   if (*itr2 == 1) {
      cout << "Erase one item of " << *itr2 << endl;
      itr2 = v.erase(itr2);    
   } else {
      itr2++;
   }
}

// 1 序列容器和无序容器的erase返回指向删除元素下一个元素的迭代器
// 2. 关联容器的erase不返回东西

总结

  • 序列容器和无序容器使用:it = c.erase(it);
  • 关联容器:c.erase(it++);

使用算法

vector<int> c = {1, 4, 1, 1, 1, 12, 18, 16};

//普通函数
bool equalOne(int e) {
   if (e == 1) {
      cout << e << " will be removed" << endl;
      return true;
   }
   return false;
}
auto itr = remove_if(c.begin(), c.end(), equalOne);
c.erase(itr, c.end());



//使用bind():
bool equalOne(int e, int pattern) {
   if (e == pattern) {
      cout << e << " will be removed" << endl;
      return true;
   }
   return false;
}
remove_if(v.begin(), v.end(), bind(equalOne, placeholders::_1, 1));



// Lambda函数:
auto itr = remove_if(v.begin(), v.end(), 
      [](int e){ 
         if(e == 1) {
            cout << e << " will be removed" <<endl; return true; 
         } 
      } 
   );

以上是关于STL进阶--删除元素的主要内容,如果未能解决你的问题,请参考以下文章

STL—— 容器(vector)元素的删除

进阶C++STL之map

坑 - stl之删除元素

仅通过迭代器删除 STL 容器元素

怎么删除STL容器的元素

C++ STL删除vector中指定元素