如何计算更改`std :: map`的签名

时间:2015-02-25 04:48:58

标签: c++ algorithm

我们有5台服务器,每台服务器运行相同的服务,生成std::mapstd::map中的每个项目都由一个唯一的整数作为键,double作为其对应的值。为了检查不同机器之间的一致性,我们需要不断检查五台服务器中std::map的相等性。

每个std::map存储了2百万个不同的商品,并且在白天不断变化。比较该值的天真方法如下:

compare S1 with S2, S3, S4, S5
compare S2 with S3, S4, S5
compare S3 with S4, S5
compare S4 with S5

这是N * N复杂度,只要地图中的单个值发生变化,就必须重做O(N)比较。

更好的想法是为每个地图构建一个签名,最后将地图比较简化为浮点数比较。这里有两个挑战:

  1. 如何基于巨大的地图构建单个值
  2. 如何根据更改的地图递增计算此值
  3. 任何建议都表示赞赏。

3 个答案:

答案 0 :(得分:2)

由于地图显然总是一致的,因此自然会发生相同的修改以相同的顺序发生。

这意味着您可以使用修改序列的(安全)哈希来代替比较地图本身。对于每次修改,您都会更新H = hash(H | Key | Value ),然后比较H1 ... H5

H的初始选择并不重要,主要要求是所有服务器应以相同的H值开始,并且映射处于相同的状态。

答案 1 :(得分:1)

根据Bryan Chen的评论,可以递增计算的简单哈希如下:

给定哈希函数h()计算h(len(k)|| k || v)其中||表示追加,len(k)是k的长度,k和v是单个键值对的键和值。然后跟踪哈希映射中所有键值对的总和或xor,在添加或删除键值对时通过递增,递减或对其进行维护来保持它。

对于知道或可以找到h(len(k)|| k || v)哈希值对的对手来说当然不安全。在其他情况下,如果h()可以建模为一个想法随机函数,它似乎是安全的 - 但在其他人看过这个想法之前我不会打赌这个。如果您担心,可以使用http://en.wikipedia.org/wiki/Hash-based_message_authentication_code和密钥来获取秘密h()。

答案 2 :(得分:0)

增量哈希显然是要走的路。

除非出于某种原因,否则不是。另一种方法是序列化和散列整个树。 Boost提供了方便的序列化功能,并且有一个可用的MD5哈希生成器here。将这两者结合起来,您可以随时对任何地图进行哈希处理。下面的代码将编译为:

g++ test.cpp md5.cpp --std=c++11 -lboost_serialization

当然,您可以将MD5哈希替换为您选择的其他哈希值。

#include <map>
#include <sstream>
#include <iostream>

#include <boost/serialization/serialization.hpp>
#include <boost/serialization/map.hpp>
#include <boost/archive/text_oarchive.hpp>

#include "md5.h"


int main()
{
  std::map<int, int> map = {{1,2}, {2,1}};
  std::stringstream ss;
  boost::archive::text_oarchive oarch(ss);
  oarch << map;

  std::cout<<md5(ss.str())<<std::endl;
}