C++ 从另一个向量中删除向量的元素

C++ 从另一个向量中删除向量的元素,c++,visual-c++,stl,C++,Visual C++,Stl,我有两个XML DOM节点向量: vector<IXMLDOMNodePtr> A; //filled in somehow vector<IXMLDOMNodePtr> B; //filled in somehow 中的remove\u if函数可以完成这项工作,但我不知道如何在这里编写谓词函数。有人知道谓词函数应该是什么样子吗 更新: 我尝试了以下代码: static MSXML2::IXMLDOMNodePtr transformIfInB(const vecto

我有两个XML DOM节点向量:

vector<IXMLDOMNodePtr> A; //filled in somehow
vector<IXMLDOMNodePtr> B; //filled in somehow
中的
remove\u if
函数可以完成这项工作,但我不知道如何在这里编写谓词函数。有人知道谓词函数应该是什么样子吗

更新:

我尝试了以下代码:

static MSXML2::IXMLDOMNodePtr transformIfInB(const vector<MSXML2::IXMLDOMNodePtr>& B,     MSXML2::IXMLDOMNodePtr ptr){return find(B.begin(), B.end(), ptr) != B.end() ? 0 : ptr;
}};

std::transform(vecCurRowItemSet.begin(),vecCurRowItemSet.end(),vecCurRowItemSet.begin(),std::bind1st(transformIfInB, vecTempItemSet));
静态MSXML2::IXMLDOMNodePtr transformIfInB(const vector&B,MSXML2::IXMLDOMNodePtr ptr){返回find(B.begin(),B.end(),ptr)!=B.end()?0:ptr;
}};
std::transform(vecCurRowItemSet.begin(),vecCurRowItemSet.end(),vecCurRowItemSet.begin(),std::bind1st(transformIfInB,vecTempItemSet));
vecCurRowItemSet和VectTempItemSet都是IXMLDOMNodePtr的向量 但我犯了以下错误:

c:\Program Files\Microsoft Visual Studio 10.0\VC\include\xfunctional(278): error C2825:     '_Fn2': must be a class or namespace when followed by '::'
1>          XMLDOMFromVCDlg.cpp(4161) : see reference to class template instantiation     'std::binder1st<_Fn2>' being compiled
1>          with
1>          [
1>              _Fn2=MSXML2::IXMLDOMNodePtr (const std::vector<MSXML2::IXMLDOMNodePtr>     &,MSXML2::IXMLDOMNodePtr)
1>          ]
c:\Program Files\Microsoft Visual Studio 10.0\VC\include\xFunction(278):错误C2825:“\u Fn2”:后跟“:”时必须是类或命名空间
1> XMLDOMFromVCDlg.cpp(4161):请参阅正在编译的类模板实例化'std::binder1st'的参考
1> 与
1>          [
1> _Fn2=MSXML2::IXMLDOMNodePtr(const std::vector&,MSXML2::IXMLDOMNodePtr)
1>          ]

如果您保证
B
A
的有序子序列,您可以自己编写:

auto j = B.begin();
for (auto i = A.cbegin(); i != A.cend(); ++i)
{
  if (*i == *j) { *i = blank; ++j; }
}
assert(j == B.end());

好的,对于一般情况,
B
的顺序不一定正确。使用谓词是不好的,因为谓词必须有一个const调用,并且我们需要操作对象(或其他一些状态变量)。因此,让我们试试上面的一个变体:

auto j = B.begin();

std::set<size_t> Bindices;
for (size_t i = 0; i < B.size(); ++i) { Bindices.insert(Bindices.end(), i); }

for (auto i = A.cbegin(); i != A.cend(); ++i)
{
  for (auto k = Bindices.begin(); k != Bindices.end(); ++k)
  {
    if (*i == B[*k]) { *i = blank; Bindices.erase(k); break; }
  }
}

assert(Bindices.empty());
auto j=B.begin();
std::设置绑定;
对于(size_t i=0;i
我怀疑标准库中是否有适合您的完美算法。工作量取决于两个向量是否预先排序,或者是否可以对它们进行排序

如果你不能对向量进行排序,那么你将处于O(n^2)区域,因为要从A中删除B中的每个元素,你必须搜索A一次才能找到它

一个好的排序是O(nlgn),所以通常预排序比不排序要快

如果性能不是问题,那么蛮力方法就是

IXMLDOMNodePtr transformIfInB(IXMLDOMNodePtr ptr) { return find(B.begin(),B.end(), ptr) != B.end() ? 0 : ptr; }
...
std::transform(A.begin(),A.end(),A.begin(),transformIfInB);
如果对这两个向量进行排序,那么最好并行遍历它们

typedef std::vector<IXMLDOMNodePtr>::iterator vecIt;
vecIt itA, itB;
std::sort(A.begin(),A.end()); 
std::sort(B.begin(),B.end());
for(itA = A.begin(), itB = B.begin(); itB != B.end() && itA != A.end(); )
{
  if(*itA < *itB) ++itA; 
  else if(*itA == *itB) *itA++ == 0;
  else if(*itA > *itB ) ++itB;
}
typedef std::vector::iterator vecIt;
维吉特itA,itB;
排序(A.begin(),A.end());
排序(B.begin(),B.end());
对于(itA=A.begin(),itB=B.begin();itB!=B.end()&&itA!=A.end();)
{
如果(*itA<*itB)+itA;
如果(*itA==*itB)*itA++==0;
否则,如果(*itA>*itB)+itB;
}

在这个循环中,我们将两个迭代器分别放在B和A中。当A小于B时,我们将A向前移动-因此我们知道A中在此之前没有元素存在于B中,因为它们是经过排序的。如果倒数为真,我们将B向前移动。如果匹配,我们将根据您的问题将元素归零。

什么是“自动”?“blank”是VC++中的关键字吗?我对这些用法真的很陌生。@Kerrek,这只在B是a的子序列(相对于子集)时才有效。
auto
是C++0x,因为你说Visual Studio我以为你有它。如果不是,则说
std::vector::const_迭代器i
std::vector::iterator j。(现在你希望你没有问过!)
blank
是你在问题中告诉我们的。。。你想放什么就放什么。嗯,我认为STL算法都只在排序范围内工作(在这种情况下,我的算法也会工作),但是如果我们要让原始范围保持有序,那么我只能考虑用更复杂的检查来替换循环体。好的,我添加了一个稍微复杂一点的版本,它跟踪
B
中元素的索引;排序(B.begin(),B.end())
在残暴力解决方案中,参数列表应该包括向量B?我的意思是我可以将transformIfInB集成到std::transform中吗,因为A和B在我的程序中都声明为局部向量。您可以使用bind1st。将谓词更改为二进制函数,并使用bind1st设置B:
IXMLDOMNodePtr transformIfInB(const std::vector&B,IXMLDOMNodePtr ptr){返回find(B.begin(),B.end(),ptr)!=B.end()?0:ptr;}std::transform(a.begin(),a.end(),a.begin(),std::bind1st(transformIfInB,B))
typedef std::vector<IXMLDOMNodePtr>::iterator vecIt;
vecIt itA, itB;
std::sort(A.begin(),A.end()); 
std::sort(B.begin(),B.end());
for(itA = A.begin(), itB = B.begin(); itB != B.end() && itA != A.end(); )
{
  if(*itA < *itB) ++itA; 
  else if(*itA == *itB) *itA++ == 0;
  else if(*itA > *itB ) ++itB;
}