【问题标题】:Compare elements between them and get the keys of common values比较它们之间的元素并获取共同值的键
【发布时间】:2018-09-26 22:31:45
【问题描述】:

我在两个不同的集合中有成对的数据、键和值。我需要比较两个集合的值,并创建一个包含相等值的键对的集合。

例如,使用以下数据集:

      Vals
Key Col1 Col2
1    4     5
2    6     9
4    8     4
6    10    10

常见的值是 4 和 10。所以他的想法是用这些对获得一个新集合,在这种情况下是 (key col1, key col2) {{1, 4}, {6, 6}}

我需要一种最快的方法来做到这一点,每个集合可以有 100k 的数据,并且使用 for 循环进行迭代太慢,我尝试使用向量。

两个集合不一定有相同的键(如 map),数据可能不是 int (我使用二进制数据,通常键是 int(unsinged long)。

这是我的示例代码(非常慢的代码):

struct p {
    unsigned long int p1;
    unsigned long int p2;
};

vector<int> table1 = tables1(n); /* bigger n -> more samples */
vector<int> table2 = tables2(n); /* n = 10000 generate 150k per table */

vector<p> common;

for (unsigned long int i = 0;i < table1.size(); i++) {
    for (unsigned long int j = 0; j < table2.size(); j++) {
        if (table1[i] == table2[j]) {common.push_back ({i, j};}
    }
}

有没有办法用地图、集合或其他东西更快地做到这一点? (我从 C++ 开始)

【问题讨论】:

  • 创建两张地图。 A 从键映射到 col1,B 从键映射到 col2。然后只比较 A[key] == B[key] 如果 key 存在于两者中
  • 你的意思是用map而不是vector做同样的事情?,在那种情况下我认为不会更快,这个算法真的很慢......
  • 应该是 O(n lgn) 而不是 O(n^2)
  • 测试了一下,还是很慢...,比较地图或者矢量图.....
  • 那你做得不对。正确的算法将同时遍历两个映射,而不是遍历第一个映射,然后每次都检查第二个映射。这是错误的。您需要同时遍历两个地图。如果你还有问题,你应该向你的老师寻求帮助,也就是给你这个作业的那个人。这就是教师的报酬,帮助学生完成家庭作业。

标签: c++ algorithm key containers matching


【解决方案1】:

实际上,您比较了它们之间的所有值,并想知道每个集合中该值的键。

在这种情况下,我建议简单地反转每个映射中的键和值。这将导致以下结构:

      Vals
RevKey1 RevVal1 RevKey2 RevVal2
4       1         5     1
6       2         9     2
8       4         4     4
10      6        10     6

然后您只需遍历第一个映射,并在第二个映射中查找相同的键:

map<int,int> col1;
map<int,int> col2;
map<int,pair<int,int>> common ; 
...
for (auto& x: col1) {
    auto y= col2.find(x.first); 
    if (y!=col2.end()) 
        common[x.first]=make_pair(x.second,y->second);
}
cout<<"Result:"<<endl;
for (auto& x:common ) 
    cout << x.first << "<-" << x.second.first << " in col1 and " <<x.second.second << " in col2"<<endl;

Online demo

备注:我让您作为练习,对现有地图中表达的映射关系进行反演。我还让你扩展这个算法来处理多映射,以防多个键具有相同的值。

【讨论】:

  • 为什么需要两张地图?
  • @PaulSanders 我使用了地图,因为 OP 的数据显示键不连续。例如没有键 3。使用vector&lt;int&gt; 你不能代表这个。此外,OP 建议数据可能与整数不同,这在地图的情况下不是问题。
  • 感谢您的回答,似乎没有内置函数(考虑不同长度的表),这会更好,我知道如何反转地图,但使用 multimap 是对我来说是新的,那将是我的练习,谢谢帮助:D
【解决方案2】:

下面的(非常简单的)代码似乎可以解决问题:

#include <map>
#include <vector>
#include <iostream>

struct p
{
    p (int p1, int p2) : p1 (p1), p2 (p2) { }
    int p1;
    int p2;
};

std::vector<int> table1;
std::vector<int> table2;
std::vector<p> common;

#define N   100000

int main ()
{
    table1.reserve (N);
    table2.reserve (N);

    for (int i = 0; i < N; ++i)
        table1.emplace_back (rand ());

    for (int i = 0; i < N; ++i)
        table2.emplace_back (rand ());

    std::map <int, int> map1;
    for (int i = 0; i < N; ++i)
        map1 [table1 [i]] = i;

    common.reserve (N);

    int n = table2.size();
    for (int i = 0; i < n; i++)
    {
        auto f = map1.find (table2 [i]);
        if (f != map1.end ())
            common.emplace_back (i, f->second);
    }

    for (auto x : common)
       std::cout << x.p1 << ", " << x.p2 << "\n";
}

输出:

12727, 93810
12766, 48493
16044, 71990
43202, 35849
46218, 81007
82512, 70112
98740, 72244

注意reserveemplace_back 用于向量。

Wandbox运行它

我尝试将 N 增加到 1000000,但它仍然有效。无序(散列)地图可能会更快。

【讨论】:

    猜你喜欢
    • 2011-02-21
    • 2016-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多