带有向量作为键的 STL 映射

Posted

技术标签:

【中文标题】带有向量作为键的 STL 映射【英文标题】:STL Map with a Vector for the Key 【发布时间】:2012-02-12 19:04:27 【问题描述】:

我正在处理一些二进制数据,这些数据存储在任意长的无符号整数数组中。我发现我有一些重复的数据,并且希望在短期内忽略重复数据,并从长远来看消除导致它们的任何错误。

我正在考虑在存储之前将每个数据集插入到地图中,但前提是在开始时在地图中找不到它。我最初的想法是拥有一个字符串映射并使用 memcpy 作为锤子将整数强制转换为字符数组,然后将其复制到字符串中并存储字符串。这失败了,因为我的大量数据在相关数据的前面包含多个字节的0(又名NULL),所以大部分非常真实的数据都被丢弃了。

我的下一次尝试计划是std::map<std::vector<unsigned char>,int>,但我意识到我不知道地图插入功能是否会起作用。

这是可行的,即使是不明智的,还是有更好的方法来解决这个问题?

编辑

所以有人说我没有说清楚我在做什么,所以这里有一个更好的描述。

我正在生成一个最小生成树,因为我有许多包含我正在使用的实际端节点的树。目标是选择长度最短且覆盖所有末端节点的树,其中所选择的树最多彼此共享一个节点并且全部连接。我的方法基于二叉决策树,但进行了一些更改以希望实现更大的并行性。

我没有采用二叉树方法,而是选择为每个数据集从无符号整数中创建一个位向量,其中位位置的 1 表示包含相应的树。

例如,如果只有树 0 包含在 5 棵树的数据集中,我会开始

00001

从这里我可以生成:

00011

00101

01001

10001

然后可以并行处理其中的每一个,因为它们都不相互依赖。我对所有单棵树(00010、00100 等)执行此操作,并且应该,我没有花时间正式证明它,能够生成范围 (0,2^n) 内的所有值一次而且只有一次。

我开始注意到许多数据集的完成时间比我想象的要长得多,并启用了一个调试输出来查看所有生成的结果,然后一个快速的 Perl 脚本确认我有多个进程产生相同的输出。从那以后,我一直在尝试解决重复项的来源,但收效甚微,我希望这能很好地让我验证生成的结果,而无需等待 3 天。计算。

【问题讨论】:

是什么阻止你尝试这个? 如果您只需要独特性,您可以考虑std::set 【参考方案1】:

你不会有问题,因为 std::vector 为你提供了“==”、“”运算符:

http://en.cppreference.com/w/cpp/container/vector/operator_cmp

【讨论】:

但是您需要一个小于运算符才能用作 map 中的键。不过,我想您可以将比较作为模板参数提供。 vector 也提供了这一点,如链接所示。我将编辑我的答案以使其更清晰。感谢您的观察。【参考方案2】:

std::map 中的 requirements for being a key 满足 std::vector,所以是的,您可以这样做。听起来像是一个很好的临时解决方案(易于编码,最少的麻烦)——但您知道他们说什么:“没有什么比临时解决方案更永久的了”。

【讨论】:

我真正希望看到的是,添加此内容后是否仍会得到重复的结果。这会将搜索范围缩小到我无意中存储或获取重复项而不是生成它们。 【参考方案3】:

正如 Renan Greinert 指出的那样,这应该可以工作,vector<> 满足用作 map 密钥的要求。

你还说:

我正在考虑在存储之前将每个数据集插入到地图中, 但前提是在地图上没有找到它。

这通常不是您想要做的,因为这将涉及在地图上执行find(),如果未找到,则执行insert() 操作。这两个操作基本上必须进行两次查找。最好尝试将项目插入到地图中。如果密钥已经存在,则根据定义,操作将失败。所以你的代码看起来像这样:

#include <vector>
#include <map>
#include <utility>

// typedefs help a lot to shorten the verbose C++ code
typedef std::map<std::vector<unsigned char>, int> MyMapType;

std::vector<unsigned char> v = ...; // initialize this somehow
std::pair<MyMapType::iterator, bool> result = myMap.insert(std::make_pair(v, 42));
if (result.second)

   // the insertion worked and result.first points to the newly 
   // inserted pair

else

   // the insertion failed and result.first points to the pair that
   // was already in the map

【讨论】:

我已经更新了原始问题,提供了更多关于我正在做什么的细节,希望这有助于澄清我的动机。老实说,我没有意识到可以像这样跳过查找,感谢我可以在 STL 中使用的很棒的新东西。 糟糕,我刚刚修复了“密钥已在地图盒中”的注释。如果键已经在映射中,那么result.second 将为假,result.first 将指向现有的键值对。【参考方案4】:

为什么需要std::map?也许我错过了一些观点,但是使用std::vectorfind 算法作为示例here 怎么样?

这意味着,您将 unsigned ints 附加到向量中,然后再搜索它,例如

std::vector<unsigned int> collector; // vector that is substituting your std::map
for(unsigned int i=0; i<myInts.size(); ++i)   // myInts are the long ints you have
    if(find(collector.begin(), collector.end(), myInts.at(i)==collector.end()) 
         collector.push_back(myInts.at(i));
    

【讨论】:

如果我可以将所有内容都放入一个无符号整数中,那就可以了。问题是,一旦我获得足够大的输入,我必须开始溢出到多个整数中,并且必须将它们保留为整个集合以进行搜索。我真的希望在没有实际制作结构来处理这个问题的情况下做到这一点,因为它希望是一个非常临时的 hack。

以上是关于带有向量作为键的 STL 映射的主要内容,如果未能解决你的问题,请参考以下文章

将本地向量复制到映射中某个键的值时遇到段错误

使用带有 STL 向量的 SSE 计算平均值

Visual C++ 2010 中的 STL 映射实现和线程安全

如何在带有向量作为值类型的地图中添加值?

将向量映射到特定范围

c++ 使用友好类的类型作为模板参数声明 stl 向量