从另一个向量中删除矢量元素

时间:2011-07-10 21:17:46

标签: c++ visual-c++ stl

我有两个XML DOM节点向量:

vector<IXMLDOMNodePtr> A; //filled in somehow
vector<IXMLDOMNodePtr> B; //filled in somehow

B是A的子集。我想从A中删除B,并且我还想保留A的顺序,这样如果A中的元素被删除,它将被替换为空元素。它看起来像这样:

node1||blank||node2||...

来自remove_if的{​​{1}}函数可以完成这项工作,但我不知道如何在这里编写谓词函数。有谁知道谓词函数应该是什么样的?

更新

我尝试了以下代码:

<algorithm>

vecCurRowItemSet和vecTempItemSet是IXMLDOMNodePtr的所有向量 但是我得到了以下错误:

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));

2 个答案:

答案 0 :(得分:2)

我怀疑标准库中有一个完美的算法。工作量取决于两个向量是否已预先排序,或者是否可以对它们进行排序。

如果你无法对矢量进行排序,那么你将被留在O(n ^ 2)区域,因为B中的每个元素都要从A中删除,你必须搜索一次以找到它。

一个好的排序是O(n lg n),所以一般来说,预排序比不排序要快。

如果表现不是问题,那么蛮力方法就是

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;
}

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

答案 1 :(得分:1)

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

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());