【问题标题】:Better(faster) algorithm to compare 2 vector of vector of integer?更好(更快)的算法来比较整数向量的 2 个向量?
【发布时间】:2018-10-13 23:46:25
【问题描述】:

我有一组原始数据文件,每个文件有 800 万~900 万行(是的, 8,000,000~9,000,000),格式如下,

1,2,3,4,5,16,23,35
1,2,3,4,6,17,23,36
1,2,3,4,7,18,23,37
1,2,3,4,8,19,23,38
1,2,3,4,9,20,23,39
1,2,3,4,10,21,23,40
1,2,3,4,11,22,23,41
1,2,3,4,12,23,24,42
1,2,3,4,13,24,25,43
1,2,3,4,14,25,26,44

每行有 8 个排序后的数字,范围为 1~49。 另一组“过滤器”文件,每个文件有 600 万到 700 万行 以下格式,

13,4,7,8,18,20
9,10,11,12,5,6,7,8,1,2,3,4,21,22,23,24,13,14,15,16,29,30,31,32,45,46,47,48
29,49,36,37,34,17,15,9,16,30,28,47,46,27,20,32,14,26,1,4,3,6,10,2,7,48,44,41

每行有 4~28 个未排序的数字,范围为 1~49 我需要将“原始数据”文件中的每一行与“过滤器”文件中的每一行进行比较 并获得交点值,例如raw 中的第 1 行,filter 中的第 1~3 行

1  // since only 4 is in common with filter line 1
7  // since only 35 not found in filter line 2
6  // since 5 23 35 not found in filter line 3    

比较后,会根据阈值输出结果。 例如

output raw data line with intersection value >= 2,
output raw data line with intersection value == 4

我知道(最多)有 900 万 x 800 万行比较。 起初,我尝试使用 set_intersection 来完成这项工作,但完成这项任务需要很长时间(过滤线在传递给 set_intersection 之前已排序)。

int res[8];
int *it = set_intersection(Raw.Data, Raw.Data+8, FilterVal.begin(), FilterVal.end(), res);
ds = GetIntersect(GDE.DrawRes, LotArr) * 2;
int IntersectCnt=it-res;

接下来,我尝试构建一个整数零数组:

int ResArr[49] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

并使用 3 个辅助函数:

void InitResArr(int * inResArr, vector<int> & FilterVal) {
    for (int i = 0; i < FilterVal.size(); i++) {
        inResArr[FilterVal[i] - 1] = 1;
    }
}
void ResetResArr(int * inResArr, vector<int> & FilterVal) {
    for (int i = 0; i < FilterVal.size(); i++) {
        inResArr[FilterVal[i] - 1] = 0;
    }
}

int GetIntersect(int * inResArr, int * inRawData) {
    int RtnVal = 0;
    for (int i = 0; i < 8; i++) {
        RtnVal+=inResArr[inRawData[i] - 1];
    }

但是这种方法仍然需要 3 个小时以上才能完成 1 个比较(1 个原始数据文件和 1 个过滤器)。 我还有 5,000 个原始数据文件和 40,000 个过滤器要处理!!! 有没有其他更好的方法来处理这个任务?谢谢。

注册表

林志峰

【问题讨论】:

  • 如果过滤器也被排序会有所帮助,也许您可​​以将其添加为预处理步骤
  • 考虑使用位域——您只有 0 到 49 范围内的数字,因此 64 位整数足以编码每行的所有可能值。交集将是按位与。交集的基数是popcount
  • 我建议你分析你的代码并找出你的瓶颈到底是哪一部分。
  • 老兄!您至少有 8e6 行可以与其他 6e6 行进行比较。这意味着 48e12 比较!即使每次比较需要 1ns=1e-9s,你也需要 48e3s,大约是 13h。我很惊讶你能做到 3 小时!
  • 另外,这是高度可并行化的,所以如果你有一个多核系统,你可能会考虑这个。

标签: c++ arrays vector intersection


【解决方案1】:

不确定它对您的情况有多好(很难从您的描述中理解您想要什么),但我想到了以下算法:

对长行进行排序。可以在O(n)中完成,其中n是单个数据行的长度,通过简单的计数。

之后,仅对过滤行中的每个数字在已排序的行上进行二进制搜索。那将是O(m * log(n)),其中m 是过滤器行数。应该比您的 O(m*n) 有很大的改进(准确地说,您还需要将所有这些复杂性乘以数据行的数量)。

另外,请注意您的 I/O,算法更新后可能会成为下一个瓶颈(如果您使用 iostreams,请不要忘记std::ios::sync_with_stdio(false)

【讨论】:

  • 如果您投反对票,请至少在 cmets 中解释原因。到目前为止,这是唯一的答案,并且没有来自作者的进一步沟通,所以我不确定我是否理解错误或者是否是其他问题。
猜你喜欢
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
  • 2012-10-04
  • 1970-01-01
  • 1970-01-01
  • 2015-08-30
  • 2020-12-02
  • 1970-01-01
相关资源
最近更新 更多