C++ 使用map::count优化算法

C++ 使用map::count优化算法,c++,optimization,map,C++,Optimization,Map,我目前有一个算法,它散列一个键,并使用map::count检查它的唯一性。如何对其进行优化?我还忘了提到这是线程化的 int coll = 0; map<long, bool> mymap; #pragma omp parallel for for (int i = 0; i < 256; i++) for (int j = 0; j < 256; j++) for (int k = 0; k < 256; k++) { string

我目前有一个算法,它散列一个键,并使用map::count检查它的唯一性。如何对其进行优化?我还忘了提到这是线程化的

int coll = 0;
map<long, bool> mymap;
#pragma omp parallel for
for (int i = 0; i < 256; i++)
  for (int j = 0; j < 256; j++)
    for (int k = 0; k < 256; k++)
    {
      string temp;
      temp = i;
      temp += j;
      temp += k;
      temp += temp;
      long myhash = hash(temp.c_str());

     if (mymap.count(myhash))
      {
        #pragma omp atomic
        coll++;
        cout << "Collision at " << i << " " << j << " " << k << endl;
      }
      else
      {
        #pragma omp critical
        mymap[myhash] = true;
      }
    }

cout << "Number of collisions: " << coll << endl;
cout << "Map size: " << mymap.size() << endl;
int coll=0;
地图我的地图;
#pragma-omp并行
对于(int i=0;i<256;i++)
对于(int j=0;j<256;j++)
对于(int k=0;k<256;k++)
{
字符串温度;
温度=i;
温度+=j;
温度+=k;
温度+=温度;
long myhash=hash(temp.c_str());
if(mymap.count(myhash))
{
#布拉格omp原子
coll++;

cout使用
insert
而不是
operator[]
。insert函数返回一对。第二个值指示是否实际插入了该值,即您可以按如下方式重写代码:

if (!mymap.insert(std::make_pair(myhash, true)).second) {
    coll++;
    cout << "Collision at " << i << " " << j << " " << k << endl;
}
if(!mymap.insert(std::make_pair(myhash,true)).second){
coll++;

cout就空间而言,您可以使用
set
而不是
map
,因为
bool
值是无用的

另外,如果您使用的是C++11,
无序集
可能会提供更好的性能

而且

temp = i;
temp += j;
temp += k;
temp += temp;

可能比使用
stringstream
甚至字符数组的开销更大。

根据散列的大小,您可以用空间换取CPU时间,只需使用布尔向量而不是映射来进行常量时间查找。如果范围为0-2563(此处唯一值的数量),它应该只需要大约2MB,因为许多实现中的STL向量会在内部将布尔向量压缩为位。当然,如果您的哈希函数可以返回非常大的值,如232甚至264,这将是无效的(或者根本不起作用)。

好吧,我在这里回答:,它是这样的:

    int coll = 0;
typedef map<long, bool> MY_MAP_TYPE;
MY_MAP_TYPE mymap;
string temp;
long myhash;
for (int i = 0; i < 256; i++)
    for (int j = 0; j < 256; j++)
        for (int k = 0; k < 256; k++)
        {
            temp = i;
            temp += j;
            temp += k;
            temp += temp;
            myhash = hash(temp.c_str());
            if( mymap.insert( MY_MAP_TYPE::value_type( myhash, true ) ).second == false)
            {
                coll++;
                cout << "Collision at " << i << " " << j << " " << k << endl;
            }
        }
int coll=0;
typedef map MY_map_TYPE;
我的地图类型我的地图;
字符串温度;
长myhash;
对于(int i=0;i<256;i++)
对于(int j=0;j<256;j++)
对于(int k=0;k<256;k++)
{
温度=i;
温度+=j;
温度+=k;
温度+=温度;
myhash=hash(temp.c_str());
if(mymap.insert(MY_MAP_TYPE::value_TYPE(myhash,true)).second==false)
{
coll++;

cout如果您只关心6个字符串,则可以通过以下方式轻松优化生成的循环:

for (int i = 0; i < 256; i++)
  for (int j = 0; j < 256; j++)
    for (int k = 0; k < 256; k++)
    {
/*
      string temp;
      temp = i;
      temp += j;
      temp += k;
      temp += temp;
      myhash = hash(temp.c_str());
*/  
      // effectively, the same as above
      const char temp[7] = {i, j, k, i, j, k, '\0'};
      myhash = hash(temp);
    }
给出此输出:

F: 3297.17ms 
G: 736.444ms 

显示了构造
std::string
(从技术上来说,这是不必要的)的版本比进行连接的版本性能要好得多。在我的例子中,不同之处在于使用了
boost::hash
(显然,使用
std::vector
而不是
std::map
std::set
,但这不会使测试偏向任何一个结果。

避免转换为字符串,因为散列值是整数且小于256,所以可以对s中的每个
i
j
k
值使用24位键。)单字节。@Chad My采用const-char*类型,使用上面的方法在256^3个键上没有冲突。也许您可以使用..另一个哈希函数?移位整数比串联字符串更有效,这意味着动态内存分配,可能会重新分配等。@Drise,当然,但您构造键的方式,在
256^3
上没有冲突正是预期的(
2^24
),这与使用
24
位键而不进行字符串转换时得到的结果完全相同。@Chad如果我太胖了,很抱歉,但你能演示一下如何做到这一点吗?串联的好处很好。我很想回到老派,使用
sprintf
@smocking,甚至是一个表或散列,因为值是有限的。因为s是固定的(
@LuchianGrigore您将如何实现
set
而不是
map
?@Drise您可以使用find查看密钥是否已经存在,然后使用insert插入一个新密钥。这似乎增加了10秒?与CPU时间相比,空间问题更少。多亏了@Tudor,我将其线程化以解决此问题,因为我想添加第四个键,给出256^4个值,以及严重缺乏RAM的问题。你说得对,冒烟。如果可以的话,我会再给你5+个字符。这加上另一个答案,似乎增加了10秒。我借用的哈希函数正好满足了我的需要。我根本不关心6个字符,但我无法想出一个方法我的整数键指向我找到的示例的const char*。另外,这会调整到4个键吗?有:冲突数:0映射大小:16777216 VM:841.797MB 22.6494870000秒没有:冲突数:0映射大小:16777216 VM:1053.76MB 21.4004230000seconds@Drise,这只会引起有关分析代码和哈希的问题实现。请参见上面的我的编辑,以获得一个概要文件(使用
-O2
优化)构建,结果符合我的预期。这是我的完整代码。我知道它在编程礼仪方面很糟糕,但这主要是我自己的娱乐项目。如图所示,我的统计数据是:碰撞次数:0地图大小:16777216虚拟机:841.801MB 9.6751800000秒
#include <iostream>
#include <vector>
#include <boost/functional/hash.hpp>
#include <x86intrin.h>

using namespace std;

uint64_t f(std::vector<uint64_t>& values)
{
    boost::hash<std::string> hasher;

    uint64_t start = __rdtsc();
    int z = 0;

    for (int i = 0; i < 256; i++)
    {
      for (int j = 0; j < 256; j++)
      {
        for (int k = 0; k < 256; k++)
        {
          string temp;
          temp = i;
          temp += j;
          temp += k;
          temp += temp;

          values[z++] = hasher(temp);
        }
      }
    }

    return (__rdtsc()) - start;
}

uint64_t g(std::vector<uint64_t>& values)
{
    boost::hash<std::string> hasher;

    uint64_t start = __rdtsc();
    int z = 0;

    for (int i = 0; i < 256; i++)
    {
      for (int j = 0; j < 256; j++)
      {
        for (int k = 0; k < 256; k++)
        {
          const char temp[7] = {i, j, k, i, j, k, '\0'};
          values[z++] = hasher(std::string(temp, 6));
        }
      }
    }

    return (__rdtsc()) - start;
}

static const double freq = 3300000000.0;
static const int elements = 1024 * 1024 * 16;

int main()
{
    std::vector<uint64_t> values_f(elements);
    std::vector<uint64_t> values_g(elements);

    uint64_t delta_f = f(values_f);
    uint64_t delta_g = g(values_g);

    cout << "F: " << (delta_f * 1000.0) / freq << "ms \n";
    cout << "G: " << (delta_g * 1000.0) / freq << "ms \n";

    for(int x = 0; x < elements; ++x)
    {
        if(values_f[x] != values_g[x])
        {
            cout << "Error: Expected "
                 << values_f[x] << " received "
                 << values_g[x] << "!\n";
        }
    }

    return 0;
}
F: 3297.17ms 
G: 736.444ms