如何通过索引和返回具有相同值的索引集来比较矢量?

时间:2017-09-17 14:04:48

标签: c++ performance vector

给定一组二元向量S,比较S中每个向量中所有元素的最有效方法是什么,并返回所有向量中具有相同值的所有索引集?

例如:

enter image description here

这里矢量水平显示,每个元素都标记为x1,x2,x3等。算法应该返回集合{x1,x8}和{x7,x9}(忽略图像中的x4和x6,与另一个问题有关。)

到目前为止,这是我的(非常hacky)解决方案:

#include <iostream>
#include <vector>
using namespace std;

int main() {

    // initialise test vectors
    std::vector<std::vector<int> > vecs;
    vecs.push_back(std::vector<int>{0,0,1,1,0,0,1,0,1});
    vecs.push_back(std::vector<int>{1,0,0,1,1,0,1,1,1});
    vecs.push_back(std::vector<int>{1,1,0,1,0,0,0,1,0});

    // vector to keep track if index already in a group
    std::vector<int> in_group (vecs[0].size(), 0);

    // output vector
    std::vector<std::vector<int> > output;

    for (int i = 0; i < vecs[0].size(); ++i){
        // if already in group, skip current index
        if (in_group[i]) continue;
        else in_group[i] = 1;

        // vector to store values in current group
        std::vector<int> curr_group {i};

        for (int j = i+1; j < vecs[0].size();++j){
            bool match = true;
            // if already in a group, continue
            if (in_group[j]) continue;
            for (int s = 0; s < vecs.size(); ++s){
                if (vecs[s][i] != vecs[s][j]){
                    match = false;
                    break;
                }
            }
            // if loop completed without breaking, match found
            if (match){
                curr_group.push_back(j);
                in_group[j] = 1;
            }

        }
        // put current group in output vector
        output.push_back(curr_group);
    }

    // display output
    for (int i = 0; i < output.size(); ++i){
        for (int j = 0; j < output[i].size(); ++j){
            std::cout << "x" << output[i][j] << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

它基本上只迭代每个索引并在每个向量上比较彼此的索引,如果它到达底部而没有不匹配,则将其添加到当前组。如果未找到匹配项,则仅为该组添加单个索引(这是所需的函数)。该函数的输出是:

x0 x7 
x1 
x2 
x3 
x4 
x5 
x6 x8 

哪个是正确的(如果你翻译每个索引的值,+ 1),那么它是有效的。我只是想知道是否有更好/更快的方法来做到这一点,可能使用花哨的数据结构或什么?我比较的向量非常大(每个向量高达一百万个值),我在很多向量(高达1000+)之间进行比较,因此效率非常重要。

非常感谢任何帮助!

3 个答案:

答案 0 :(得分:0)

这些方面的一些东西,也许是:

#include <iostream>
#include <vector>
#include <bitset>
#include <unordered_map>

int main() {

    // initialise test vectors
    std::vector<std::vector<int> > vecs;
    vecs.push_back(std::vector<int>{0,0,1,1,0,0,1,0,1});
    vecs.push_back(std::vector<int>{1,0,0,1,1,0,1,1,1});
    vecs.push_back(std::vector<int>{1,1,0,1,0,0,0,1,0});

    std::unordered_map<unsigned, std::vector<int>> groups;

    for (int i = 0; i < vecs[0].size(); ++i){
        unsigned key = 0;
        for (int j = 0; j < vecs.size(); ++j) {
            key += vecs[j][i] << j;
        }
        groups[key].push_back(i);
    }


    // display output
    for (const auto& group : groups) {
        for (auto index : group.second) {
            std::cout << "x" << index << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

答案 1 :(得分:0)

如何创建一组记录具有给定序列的索引集的向量。每个阶段根据下一个二进制值拆分每个向量,从而消除任何减少到大小为1的向量。

stage 1:
split { 1,2,3,4,5,6,7,8,9 }
<0> -> { 1,2,5,6,8 }
<1> -> { 3,4,7,9 }
stage 2:
split { 1,2,5,6,8 }
<0> -> { 2,6 }
<1> -> { 1,5,8 }
split { 3,4,7,9 }
<0> -> { 3 }  <-- eliminate as size is 1
<1> -> { 4,7,9 }
stage 3:
split { 2,6 } 
<0> -> { 6 }   <-- eliminate as size is 1
<1> -> { 2 }   <-- eliminate as size is 1
split { 1,5,8 }
<0> -> { 5 }   <-- eliminate as size is 1
<1> -> { 1,8 }
split { 4,7,9 }
<0> -> { 7,9 }
<1> -> { 4 }  <-- eliminate as size is 1

请注意,您不需要记录序列,只需根据当前二进制矢量中的值拆分前一阶段的矢量。最糟糕的情况是您检查一次数组的每个元素,因此复杂度为O(n)。

答案 2 :(得分:0)

首先,将每列转换为对象。您需要能够对每两个对象执行比较。任何&#34;大整数&#34;实施应该足够了。

使用这些,构建一对对的向量,由列索引和大型int组成。

按大整数对此向量进行排序,现在所有匹配的列都在向量中。

最后迭代一次,找到每组相同的列,然后就完成了。

此算法的运行时复杂度仅为O(n log n),这比当前的O(n ^ 3)实现速度快。