首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >std::向量差异

std::向量差异
EN

Stack Overflow用户
提问于 2011-10-15 02:14:17
回答 2查看 16.1K关注 0票数 16

如何确定两个向量的差异?

我有vector<int> v1vector<int> v2

我要找的是一个只包含v1v2元素的vector<int> vDifferences

有没有一种标准的方法来做到这一点?

EN

Stack Overflow用户

回答已采纳

发布于 2011-10-16 05:05:30

这是完整的正确的答案。在使用set_symmetric_difference算法之前,必须对源范围进行排序:

代码语言:javascript
复制
  using namespace std; // For brevity, don't do this in your own code...

  vector<int> v1;
  vector<int> v2;

  // ... Populate v1 and v2

  // For the set_symmetric_difference algorithm to work, 
  // the source ranges must be ordered!    
  vector<int> sortedV1(v1);
  vector<int> sortedV2(v2);

  sort(sortedV1.begin(),sortedV1.end());
  sort(sortedV2.begin(),sortedV2.end());

  // Now that we have sorted ranges (i.e., containers), find the differences    
  vector<int> vDifferences;

  set_symmetric_difference(
    sortedV1.begin(),
    sortedV1.end(),
    sortedV2.begin(),
    sortedV2.end(),
    back_inserter(vDifferences));

  // ... do something with the differences

应该注意的是,排序是一个开销很大的操作(即O(n log n) for common STL implementations)。特别是对于容器中的一个或两个都非常大(即,数百万个整数或更多)的情况,基于算法复杂度,使用散列表的不同算法可能是优选的。以下是该算法的高级描述:

  1. 将每个容器加载到一个哈希表中。如果两个容器的大小不同,则在步骤3中使用较小的一个对应的哈希表进行遍历。否则,将两个哈希表中的第一个哈希表used.
  2. Traverse到步骤2中选择的哈希表中,检查每一项是否都存在于两个哈希表中。如果是,请将其从这两个文件中删除。较小的哈希表用于遍历的原因是因为哈希表查找的平均值为O(1),而与容器大小无关。因此,遍历的时间是n的线性函数(即,O(n)),其中n是散列表的大小,该散列表是对散列表中剩余项的并集进行traversed.
  3. Take并将结果存储在差异容器中。

通过标准化unordered_multiset容器,C++11为我们提供了这样的解决方案的一些功能。我还使用了auto关键字的新用法进行显式初始化,以使以下基于哈希表的解决方案更简洁:

代码语言:javascript
复制
using namespace std; // For brevity, don't do this in your own code...

// The remove_common_items function template removes some and / or all of the
// items that appear in both of the multisets that are passed to it. It uses the
// items in the first multiset as the criteria for the multi-presence test.
template <typename tVal>
void remove_common_items(unordered_multiset<tVal> &ms1, 
                         unordered_multiset<tVal> &ms2)
{
  // Go through the first hash table
  for (auto cims1=ms1.cbegin();cims1!=ms1.cend();)
  {
    // Find the current item in the second hash table
    auto cims2=ms2.find(*cims1);

    // Is it present?
    if (cims2!=ms2.end())
    {
      // If so, remove it from both hash tables
      cims1=ms1.erase(cims1);
      ms2.erase(cims2);
    }
    else // If not
      ++cims1; // Move on to the next item
  }
}

int main()
{
  vector<int> v1;
  vector<int> v2;

  // ... Populate v1 and v2

  // Create two hash tables that contain the values
  // from their respective initial containers    
  unordered_multiset<int> ms1(v1.begin(),v1.end());
  unordered_multiset<int> ms2(v2.begin(),v2.end());

  // Remove common items from both containers based on the smallest
  if (v1.size()<=v2.size)
    remove_common_items(ms1,ms2);
  else
    remove_common_items(ms2,ms1);

  // Create a vector of the union of the remaining items
  vector<int> vDifferences(ms1.begin(),ms1.end());

  vDifferences.insert(vDifferences.end(),ms2.begin(),ms2.end());

  // ... do something with the differences
}

为了确定哪种解决方案更适合特定情况,分析这两种算法将是一个明智的行动过程。虽然基于哈希表的解决方案是O(n),但它需要更多的代码,并且每次找到重复项都要做更多的工作(即哈希表删除)。它还(遗憾地)使用了一个自定义的差分函数,而不是标准的STL算法。

应该注意的是,这两种解决方案的不同之处很可能与元素在原始容器中出现的顺序完全不同。有一种方法可以通过使用哈希表解决方案的变体来解决此问题。下面是高级描述(仅在步骤4中与前面的解决方案不同):

  1. 将每个容器加载到哈希表中。如果两个容器的大小不同,则在步骤3中将使用较小的哈希表进行遍历。否则,将对步骤2中选择的哈希表执行used.
  2. Traverse
  3. ,检查是否每一项都存在于两个哈希表中。如果是,请将其从这两个文件中删除。
  4. 要形成差异容器,请按顺序遍历原始容器(即,第一个容器在第二个容器之前)。在各自的哈希表中查找每个容器中的每个项。如果找到它,该项将被添加到差异容器中,并从其哈希表中删除。不存在于相应哈希表中的项将被跳过。因此,只有哈希表中存在的项才会在差异容器中结束,并且它们的出现顺序将保持与原始容器中相同,因为这些容器决定了最终遍历的顺序。

为了保持原来的顺序,步骤4已经变得比以前的解决方案更昂贵,特别是当删除的项目数量很多时。这是因为:

  1. 将第二次测试所有项是否有资格出现在差异容器中,方法是在其各自的哈希表中进行存在测试。
  2. 作为项1的差异测试的一部分,哈希表将在形成差异容器时逐个删除其其余项。
票数 14
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7771796

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档