C ++数组交集

时间:2011-06-01 14:36:43

标签: c++ stl hashtable intersection

有谁知道是否可以将其从O(m * n)转为O(m + n)?

    vector<int> theFirst;
    vector<int> theSecond;
    vector<int> theMatch;

    theFirst.push_back( -2147483648 );
    theFirst.push_back(2);
    theFirst.push_back(44);
    theFirst.push_back(1);
    theFirst.push_back(22);
    theFirst.push_back(1);

    theSecond.push_back(1);
    theSecond.push_back( -2147483648 );
    theSecond.push_back(3);
    theSecond.push_back(44);
    theSecond.push_back(32);
    theSecond.push_back(1);

    for( int i = 0; i < theFirst.size(); i++ )
    {
        for( int x = 0; x < theSecond.size(); x++ )
        {
            if( theFirst[i] == theSecond[x] )
            {
                theMatch.push_back( theFirst[i] );
            }
        }
    }

6 个答案:

答案 0 :(得分:5)

将第一个向量的内容放入哈希集,例如std::unordered_set。那是O(m)。扫描第二个向量,检查值是否在unordered_set中并保持其中的值。这是哈希结构的n次查找,所以O(n)。所以,O(m + n)。如果重叠中有l个元素,则可以计算O(l)以将它们添加到第三个向量。 std::unordered_set位于C ++ 0x草案中,可在最新的gcc版本中使用,boost中也有一个实现。

已编辑以使用unordered_set

使用C ++ 2011语法:

unordered_set<int> firstMap(theFirst.begin(), theFirst.end());

for (const int& i : theSecond) {
   if (firstMap.find(i)!=firstMap.end()) {
     cout << "Duplicate: " << i << endl;
     theMatch.push_back(i);
   }
}

现在,问题仍然存在,你想对原件中的重复做什么?明确地,1应该theMatch次,1次,2次或4次? 这输出:

Duplicate: 1
Duplicate: -2147483648
Duplicate: 44
Duplicate: 1

答案 1 :(得分:2)

使用此:http://www.cplusplus.com/reference/algorithm/set_intersection/

你应该能够实现O(mlogm + nlogn)我相信。 (set_intersection要求输入范围已经排序)。 但是,这可能与您对重复元素的解决方案的执行方式略有不同。

答案 2 :(得分:0)

假设您想要从两个数据集中生成theMatch,并且您不关心数据集本身,请将其放在unordered_map中(目前可从Boost获得并列在最终委员会中)草案为C ++ 11),将键映射到一个整数,该整数在添加时会增加,因此会跟踪密钥出现的次数。然后,当你对其他数据集进行点击时,你push_back命中它在第一次出现的次数。

您可以通过首先对向量进行排序来获得O(n log n + m log m),或者通过创建其中一个向量来获得O(n log n + m)。

警告:这些不是保留订单的操作,std::map将以不同的顺序以不同的技术出现。在我看来,订单可能被认为是任意的。如果上面的代码中给出的顺序是必要的,我认为没有更好的算法。

编辑:

获取类型为Type的数据集A和数据集B.创建theMatch

浏览数据集A,并检查每个成员以查看它是否在地图中。如果没有,请将带有unordered_map<Type, int> 1的元素添加到地图中。如果是,则递增int。这些操作中的每一个平均为O(1),因此该步骤为O(len A)。

浏览数据集B,并检查每个成员以查看它是否在地图中。如果没有,继续下一步。如果是,则int成员进入目标队列。 push_back是数据集A中值的次数,int成员在A中复制给定行为的次数也是如此。这些操作中的每一个都是平均O(1),因此该步骤是O(len B)。

这是平均行为。如果你总是遇到最糟糕的情况,你会回到O(m * n)。我认为没有办法保证O(m + n)。

答案 3 :(得分:0)

如果我错了,请纠正我, 你建议以下解决交叉问题: 对两个向量进行排序,并在两个排序向量中保持迭代,使得我们到达一个公共元素, 所以整体复杂性会如此 (n * log(n)+ m * log(m))+(n + m) 假设k * log(k)为排序的复杂性

我是对的吗? 当然,复杂性将取决于排序的复杂性。

答案 4 :(得分:0)

我会对较长的数组O(n * log(n))进行排序,从较短的数组O(m * log(n))中搜索元素。那么总是O(n * log(n)+ m * log(n))

答案 5 :(得分:-1)

如果结果数组/集中元素的顺序无关紧要,那么答案是肯定的。

对于定义了某个顺序的任意类型的元素,最佳算法是O( max(m,n)*log(min(m,n)) )。对于有限大小的数字,最佳算法为O(m+n)

  • 构造较小数组的元素集 - 对于任意元素,只需排序即可,对于有限大小的数字,它必须与数字排序中的中间表类似。

  • 迭代更大的数组并检查该元素是否在前面构造的集合中 - 对于任意元素二进制搜索是OK(O(log(min(n,m))),对于数字,单个检查是O(1)