给定一组二元向量S,比较S中每个向量中所有元素的最有效方法是什么,并返回所有向量中具有相同值的所有索引集?
例如:
这里矢量水平显示,每个元素都标记为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+)之间进行比较,因此效率非常重要。
非常感谢任何帮助!
答案 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)实现速度快。