如何有效地从vector中删除元素
How to efficiently delete elements from vector c++
我有一个由一对向量(V1,V2)组成的名为pairV1V2的向量,其形式如下:
(1,2,3),(938,462,4837) -> (V1,V2)
(3,9,13),(938,0472,944)
(81,84,93),(938,84,845)
那么我需要保留以下内容:
(1,2,3),(938,462,4837) -> (V1,V2)
(3,9,13),(938,0472,944)
(81,84,93),(84,845)
我需要从头开始扫描pairV1V2,在任何两个V1不相等的地方,我需要从V2中删除相交的元素。我编写了下面的代码来做同样的事情。然而,我的代码结果是非常低效的,因为我的向量pairV1V2很大,它在V2中有许多元素(大约十亿)。
int main(int argc, char** argv) {
std::vector<std::pair<std::vector<unsigned>, std::vector<unsigned> > > pairV1V2;
std::vector<std::pair <std::vector<unsigned>,std::vector<unsigned> > >::iterator itm2,lm2=pairV1V2.end();
for(std::vector<std::pair <std::vector<unsigned>,std::vector<unsigned> > >::iterator itm=pairV1V2.begin(), lm=pairV1V2.end(); itm!=lm; ++itm)
{
//Outer values
vector<unsigned> outerV1=(*itm).first;
vector<unsigned> outerV2=(*itm).second;
sort(outerV2.begin(), outerV2.end());
itm2=itm;
itm2++;
for(itm2;itm2!=lm2;++itm2)
{
vector<unsigned> innerV1=(*itm2).first;
vector<unsigned> innerV2=(*itm2).second;
vector<unsigned> setDiffV1;
std::set_difference(innerV1.begin(), innerV1.end(), outerV1.begin(), outerV1.end(),
std::inserter(setDiffV1, setDiffV1.end()));
if(setDiffV1.size()==0) //check whether any two V1's are different
{
sort(innerV2.begin(), innerV2.end());
if((itm->second.size()!=0)&&(itm2->second.size()!=0)){
std::vector<unsigned> delIntersectingElem;
std::set_intersection(outerV2.begin(),outerV2.end(),innerV2.begin(), innerV2.end(),
std::back_inserter(delIntersectingElem));
if(delIntersectingElem.size()!=0) //if there are intersecting V2's
{
for(std::vector<unsigned>::iterator its=(itm2->second).begin(),ls=(itm2->second).end();its!=ls;)
{
//if *its is present in delIntersectingElem then delete it.
if(!(std::find(delIntersectingElem.begin(), delIntersectingElem.end(), (*its)) == delIntersectingElem.end()))
{
(itm2->second).erase(its); //delete intersecting elements from inner v2
ls--;
}else{
++its;
}
}
}
}
}
}
}
return 0;
}
有人可以帮助我改进我现在的代码-它给出了正确的答案(在这个例子中,我可能错过了一些简短的情况-但代码处理所有这些),但非常慢(作为perf的对角化)。如果对我目前的代码片段提出改进建议,我将不胜感激。但是,如果两个代码的逻辑相同,则也可以采用新的算法
有一种未充分利用的STL算法,称为remove_if
,它允许您有效地(O(n))从容器中删除与谓词匹配的所有元素。如果你有一个vector
或deque
,它是最有用的,因为它们有一个昂贵的(O(n))擦除操作的元素"在中间"。但是,您需要注意,remove_if
实际上并不擦除任何元素,它只是将不匹配谓词的所有元素移动到您指定的范围的前面。因此,执行"erase_if
"的规范方法是(在本例中,所有奇数将被擦除):
std::vector ints = …;
ints.erase(std::remove_if(begin(ints), end(ints), [](int i) { return i%2 != 0; }), end(ints));
解释:remove_if
将所有与谓词不匹配的整数(即本例中的偶数整数)移到前面,并返回这些元素中最后一个的迭代器。然后,实际上使用vector<int>::erase
的范围重载擦除从这一个开始到vector末尾的所有元素。
。,假设我们有ints == {5,7,4,10,9,16,20,6}
。remove_if
将把ints
变成{4,10,16,20,6,UNSPEC,UNSPEC,UNSPEC}
,其中我使用UNSPEC
来表示任何未指定的值,它还将返回一个指向UNSPEC
第一个元素的迭代器。然后,擦除所有未指定值的元素,得到所需结果{4,10,16,20,6}
。
更新:关于之前的答案,我想指出remove_if
是稳定的,即它不会改变剩余元素的顺序。
从vector中删除元素的最有效方法是反向交换技巧,但这只适用于不关心顺序的情况。
#include <vector>
#include <iostream>
int main()
{
std::vector<int> v { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
auto it = v.begin() + 5;
// replace the current element with the back of the vector,
// then shrink the size of the vector by 1.
*it = std::move(v.back());
v.pop_back();
for (auto n : v) {
std::cout << n << " ";
}
std::cout << "n";
}
http://ideone.com/0jbWHZ 如果你知道将会有很多次删除操作或者一个非常大的向量,你可以通过使用这个技巧来保持效率,记住不要在执行一次删除操作后++当前迭代器,并在到达末端时std::sort()
vector。
—Edit—
#include <algorithm>
#include <iostream>
#include <vector>
//! Efficiently remove an element from a vector without
//! preserving order. If the element is not the last element
//! in the vector, transfer the last element into its position
//! using a move if possible.
//! Regardless, we then shrink the size of the vector deleting
//! the element at the end, which will either be destructed or
//! the element we were deleting.
//! @note: Effectively invalidates the current iterator.
template<class ValueType>
bool unstable_remove(
typename std::vector<ValueType>& container,
typename std::vector<ValueType>::iterator it
)
{
// Leave in-situ if we are already the tail element.
auto lastEl = container.end() - 1;
if (it != lastEl) {
// overwrite this element with what is in the last,
// which should have the same effect as deleting this.
*it = std::move(*lastEl);
}
// release the last cell of the vector, because it should
// now either be destructed or contain the value we were
// deleting.
container.pop_back();
}
int main()
{
std::vector<int> ints { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
auto it = ints.begin();
while (it != ints.end()) {
if ((*it % 3) == 0) {
unstable_remove(ints, it);
// do not pass go / ++it
continue;
}
++it;
}
std::cout << "after removes:n";
for (auto val : ints)
std::cout << val << " ";
std::cout << "n";
std::sort(ints.begin(), ints.end());
std::cout << "after sort:n";
for (auto val : ints)
std::cout << val << " ";
std::cout << "n";
}
生产(http://ideone.com/hGZPOC)
after removes:
1 2 10 4 5 8
after sort:
1 2 4 5 8 10
—Edit 2—
这是为了可读性清理你的代码,我也抛弃了你的结束捕获,因为…您正在删除元素。
#include <vector>
#include <cstdint>
using vec_t = std::vector<uint32_t>;
using vecpair_t = std::pair<vec_t, vec_t>;
using pairvec_t = std::vector<vecpair_t>;
int main(int argc, char** argv) {
pairvec_t pairV1V2;
for(auto itm = pairV1V2.begin(); itm != pairV1V2.end(); ++itm)
{
//Outer values
auto& outerV1 = itm->first; // NOTE '&' - reference not copy!
auto& outerV2 = itm->second;
sort(outerV2.begin(), outerV2.end());
for(auto itm2 = itm + 1; itm2 != pairV1V2.end(); ++itm2)
{
auto& innerV1 = itm2->first;
auto& innerV2 = itm2->second;
vec_t setDiffV1;
至于另一种优化方法-因为你的列表是排序的-同时遍历两个列表比较值。
template<typename ValueType>
void dedupe_vectors(
typename std::vector<ValueType>& lhs,
typename std::vector<ValueType>& rhs
)
{
auto lit = lhs.begin();
auto rit = rhs.begin();
while (rit != rhs.end) {
while (lit != lhs.end() && *lit < *rit)
++lit;
if (lit == lhs.end())
break;
if (*lit == *rit) {
v2.erase(rit);
continue;
}
++rit;
}
}
我知道-我们测试lit
和lhs.end
两次。看看编译器使用-O3生成的代码,看看它自己是否没有检测到这一点。如果是,那么你可以考虑优化它。
- 如何从存储在std::映射中的std::集中删除元素
- 从嵌套在std::映射中的std::列表中删除元素的最佳方式
- 从矢量中删除元素后出现隔离错误
- 如何使用remove_if从矢量中删除元素
- 如何从使用 for 循环中的矢量大小的矢量中删除元素
- C++映射不删除元素
- 如何从标准::元组中删除元素?
- 在动态数组中添加/删除C++元素
- 如何通过比较彼此的成员从QStringList中删除元素
- 如何修复从矢量中删除元素的错误?
- 从 std::set 中删除元素,同时在 C++17 中迭代该元素
- 使用remove_if从矢量中删除元素
- 用C++从三维矢量中删除元素
- 从对象数组中删除元素
- 如何在不使用 vector::erase() 的情况下编写自定义 Vector 方法来删除元素?
- C++ - 按自定义数据类型向量的值删除元素
- 从任意容器中廉价删除元素的惯用方法?
- 从数组中删除元素不起作用的函数
- 删除元素 BST
- 从向量中删除元素时未处理的异常