C++ 使用map::count优化算法
我目前有一个算法,它散列一个键,并使用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
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