我现在一直在编写一个图像处理算法,在某些时候我需要收集一些关于转换像素的统计信息,以便更深入地了解我应该遵循的进一步开发方向.我需要收集的信息格式如下:
key: RGB value
value: int

我做了什么,是我打开转换后的图像并通过它迭代,将我需要的值保存到具有以下签名的std :: unordered_map:

typedef std::unordered_map<boost::gil::rgb8_pixel_t,unsigned int> pixel_map_t;

在循环中:

for(int y = 0; y < vi.height(); y++) {
    SrcView::x_iterator dst_it = src.row_begin(y);
    for(int x = 0; x < vi.width(); x++,hits++) {
        diff_map.insert(std::make_pair(dst_it[x],/* some uint32 */));
    }

我还写了一个自定义哈希函数(它是一个完美的哈希函数:256 ^ 2 x R 256 x G.
B – 所以无论桶和哈希表的布局如何(合理的延伸),冲突都应该是最小的.

我注意到的是,插入速度非常慢! – 在达到第11次迭代后,插入速度降低约100倍.我发生了大量的碰撞!
尽管图像中的重复颜色数量非​​常少.

之后,我想消除代码中的任何可能的错误,并开始使用带有原始键类型(如int)的STL哈希函数对unordered_map进行基准测试.

该基准的代码是:

std::size_t hits = 0,colls = 0;
for(int y = 0; y < vi.height(); y++) {
    SrcView::x_iterator dst_it = src.row_begin(y);

    for(int x = 0; x < vi.width(); x++,hits++) {
        if(diff_map.find(x*y) != diff_map.cend())
            colls++;
        diff_map.insert(std::make_pair(x*y,10));
    } 
    std::cout << y << "/" << vi.height() << " -> buckets: " 
              << diff_map.bucket_count() << "(" 
              << std::floor(diff_map.load_factor() * 100) 
              << "% load factor) [ " << colls << " collisions / " <<  hits << " hits ]"  << std::endl;
}

…以下是外部循环的前20次迭代的结果(仅对ST型键使用STL的散列函数):

0/480 -> buckets: 8(12% load factor) [ 639 collisions / 640 hits ]
1/480 -> buckets: 4096(15% load factor) [ 640 collisions / 1280 hits ]
2/480 -> buckets: 4096(23% load factor) [ 960 collisions / 1920 hits ]
3/480 -> buckets: 4096(31% load factor) [ 1281 collisions / 2560 hits ]
4/480 -> buckets: 4096(37% load factor) [ 1654 collisions / 3200 hits ]
5/480 -> buckets: 4096(45% load factor) [ 1964 collisions / 3840 hits ]
6/480 -> buckets: 4096(51% load factor) [ 2370 collisions / 4480 hits ]
7/480 -> buckets: 4096(59% load factor) [ 2674 collisions / 5120 hits ]
8/480 -> buckets: 4096(65% load factor) [ 3083 collisions / 5760 hits ]
9/480 -> buckets: 4096(71% load factor) [ 3460 collisions / 6400 hits ]
10/480 -> buckets: 4096(77% load factor) [ 3872 collisions / 7040 hits ]
11/480 -> buckets: 4096(85% load factor) [ 4161 collisions / 7680 hits ]
12/480 -> buckets: 4096(90% load factor) [ 4612 collisions / 8320 hits ]
13/480 -> buckets: 4096(99% load factor) [ 4901 collisions / 8960 hits ]
14/480 -> buckets: 32768(13% load factor) [ 5315 collisions / 9600 hits ]
15/480 -> buckets: 32768(13% load factor) [ 5719 collisions / 10240 hits ]
16/480 -> buckets: 32768(14% load factor) [ 6148 collisions / 10880 hits ]
17/480 -> buckets: 32768(15% load factor) [ 6420 collisions / 11520 hits ]
18/480 -> buckets: 32768(16% load factor) [ 6870 collisions / 12160 hits ]
19/480 -> buckets: 32768(17% load factor) [ 7135 collisions / 12800 hits ]
20/480 -> buckets: 32768(17% load factor) [ 7584 collisions / 13440 hits ]
21/480 -> buckets: 32768(18% load factor) [ 7993 collisions / 14080 hits ]

在这种情况下,碰撞次数是否过高? STL库通常具有高质量,但对于简单的基于int的键音具有639/640和640/1280至少是奇怪的.
或者也许我做错了什么?

这是我的哈希函数(理论上,应该没有碰撞 – 但数字非常接近):

template<> 
struct std::hash<boost::gil::rgb8_pixel_t> :
    public std::unary_function<const boost::gil::rgb8_pixel_t&,size_t>
{
    size_t operator()(const boost::gil::rgb8_pixel_t& key) const
    {
        size_t ret =  (static_cast<size_t>(key[0]) << 16) |
                      (static_cast<size_t>(key[1]) << 8) |
                      (static_cast<size_t>(key[2]));
        //return 256 * 256 * key[0] + 256 * key[1] + key[2];
        return ret;
    }
};

现在,这不再有趣了……

我写了这个哈希函数:

template<> 
struct std::hash<int> :
    public std::unary_function<const int&,size_t>
{
    size_t operator()(const int& key) const
    {
        return 5;
    }
};

从理论上讲,我应该有100%的碰撞率,对吗?但结果是:

0/480 -> buckets: 8(12% load factor) [ 639 collisions / 640 hits ]
1/480 -> buckets: 4096(15% load factor) [ 640 collisions / 1280 hits ]
2/480 -> buckets: 4096(23% load factor) [ 960 collisions / 1920 hits ]
3/480 -> buckets: 4096(31% load factor) [ 1281 collisions / 2560 hits ]
4/480 -> buckets: 4096(37% load factor) [ 1654 collisions / 3200 hits ]
5/480 -> buckets: 4096(45% load factor) [ 1964 collisions / 3840 hits ]
6/480 -> buckets: 4096(51% load factor) [ 2370 collisions / 4480 hits ]
7/480 -> buckets: 4096(59% load factor) [ 2674 collisions / 5120 hits ]
8/480 -> buckets: 4096(65% load factor) [ 3083 collisions / 5760 hits ]
9/480 -> buckets: 4096(71% load factor) [ 3460 collisions / 6400 hits ]

为什么?

环境:MSVS2010

解决方法

colls不测量碰撞.如果要测量冲突,则对于[0,bucket_count())范围内的每个桶b,获取bucket_size(b).这将告诉你每个桶中有多少项.如果存储桶中有2个或更多项目,则表示存在bucket_size(b) – 存储桶b的1个冲突.

c – 悲惨的unordered_map插入性能/散列函数的更多相关文章

  1. 散列函数从整数坐标对提供唯一的uint

    认为它是一个大的白色画布上撒上黑点。这带来了哈希的想法:理想:我需要一个采用2D点的哈希函数,返回一个唯一的uint32。你可以假设的数量画布上的点很容易被uint32计数。最好的祝福,安德烈亚斯编辑:我不得不在问题文本中改变一些东西:我改变了“能够计算画布点数”的假设与uint32“成”能够计数画布上的点由uint32。如果要将两个uint32的哈希值混合成一个uint32,不要使用像Y&0xFFFF因为丢弃一半的位。

  2. php – MySQL散列函数实现

    我本来在这个问题上偶然发现我自己寻找一个PHP实现的两个MysqL密码哈希函数.我无法找到任何实现,所以我自己从MysqL源代码修改了自己.以下测试和工作在PHP5.2:希望别人会发现这个有用的:)

  3. java – 一个好的哈希函数,用于访问整数,字符串?

    我在面试中遇到了一些情况,我需要使用整数或字符串的哈希函数.在这种情况下,我们应该选择哪些?我在这些情况下出错了,因为我最终选择了那些产生大量碰撞的东西,然后哈希函数往往是数学的,你不能在面试中回忆一下.有没有一般的建议,至少面试官对你的整数或字符串输入的方法感到满意?如果相等的实例具有不等的哈希码,可以弄清楚为什么并解决问题.

  4. 散列表实现的哈希算法

    我正在寻找具有良好分布的高速散列函数,用于散列表实现.散列表将专门用于存储具有整数键的值.我可以使用整数的较低几位作为哈希吗?例如intkey=n&15;并创建一个带有16个插槽的阵列来存储它们.任何建议?解决方法你可以看这里xxhash你提到的哈希函数非常快,但它也是非常糟糕的.如果你想要一个“愚蠢”的哈希函数,也许你可以考虑模数.例:

  5. 哈希表 – 分析目标并选择一个好的哈希函数

    让我们来谈谈哈希函数,以及如何选择哈希函数.如果一个编程菜鸟需要为他们的特定任务选择一个好的哈希函数,那么选择一个呢?

  6. c – 为什么不能用std :: unordered_map替换std :: map

    解决方法我猜这是因为std::unordered_map需要重新构建,因此复制元素,类型需要完成,而只有使用指向元素的地图才会出现这样的问题.这里的解决方案是将无序映射映射到指针:

  7. c – 悲惨的unordered_map插入性能/散列函数

    尽管图像中的重复颜色数量非常少.之后,我想消除代码中的任何可能的错误,并开始使用带有原始键类型的STL哈希函数对unordered_map进行基准测试.该基准的代码是:…STL库通常具有高质量,但对于简单的基于int的键音具有639/640和640/1280至少是奇怪的.或者也许我做错了什么?这是我的哈希函数:现在,这不再有趣了……我写了这个哈希函数:从理论上讲,我应该有100%的碰撞率,对吗?

  8. 将C#散列函数转换为PHP

    )或者更可能首先转换为其他东西.在这种情况下,可能是unicode,它绝对不是字符串与.net请求的字符串相同的字节.我的建议是确保PHP也使用ASCII,withiconv,以实现互操作性.我不能确定上面的代码会输出所需的哈希值,但是,因为我没有.net方便测试初始代码.但这可能会指向正确的方向.如果这不起作用,iconv_get_encoding中的值(可能是罪魁祸首,请尝试“output_encoding”或“input_encoding”.您也可能需要使用iconv_set_encoding(.)

  9. c# – 反转哈希函数

    我有以下哈希函数,我试图让我的方法来反转它,以便我可以从哈希值中找到密钥.代码在C#中,但我认为很清楚.我知道,对于一个散列值,可以有多个键,但我的意图不是找到它们,只需要满足散列函数就足够了.编辑:函数接受的字符串仅由数字0到9以及字符’*’和’#’组成,因此Unhash函数也必须遵守此条件.有任何想法吗?

  10. c – unordered_map – 哈希函数没有影响

    为什么在下面的哈希函数似乎没有任何效果?解决方法你误解了使用哈希函数:它不用于比较元素.在内部,地图将元素组织成桶,散列函数用于确定元素所在的桶.使用另一个模板参数执行元素的比较,查看unordered_map模板的完整声明:后面的模板参数是hasher后的关键比较器.要获得您期望的行为,您必须执行以下操作:现在你的地图将有一个单一的元素,所有的结果将是3.

随机推荐

  1. 从C到C#的zlib(如何将byte []转换为流并将流转换为byte [])

    我的任务是使用zlib解压缩数据包(已接收),然后使用算法从数据中生成图片好消息是我在C中有代码,但任务是在C#中完成C我正在尝试使用zlib.NET,但所有演示都有该代码进行解压缩(C#)我的问题:我不想在解压缩后保存文件,因为我必须使用C代码中显示的算法.如何将byte[]数组转换为类似于C#zlib代码中的流来解压缩数据然后如何将流转换回字节数组?

  2. 为什么C标准使用不确定的变量未定义?

    垃圾价值存储在哪里,为什么目的?解决方法由于效率原因,C选择不将变量初始化为某些自动值.为了初始化这些数据,必须添加指令.以下是一个例子:产生:虽然这段代码:产生:你可以看到,一个完整的额外的指令用来移动1到x.这对于嵌入式系统来说至关重要.

  3. 如何使用命名管道从c调用WCF方法?

    更新:通过协议here,我无法弄清楚未知的信封记录.我在网上找不到任何例子.原版的:我有以下WCF服务我输出添加5行,所以我知道服务器是否处理了请求与否.我有一个.NET客户端,我曾经测试这一切,一切正常工作预期.现在我想为这个做一个非托管的C客户端.我想出了如何得到管道的名称,并写信给它.我从here下载了协议我可以写信给管道,但我看不懂.每当我尝试读取它,我得到一个ERROR_broKEN_P

  4. “这”是否保证指向C中的对象的开始?

    我想使用fwrite将一个对象写入顺序文件.班级就像当我将一个对象写入文件时.我正在游荡,我可以使用fwrite(this,sizeof(int),2,fo)写入前两个整数.问题是:这是否保证指向对象数据的开始,即使对象的最开始可能存在虚拟表.所以上面的操作是安全的.解决方法这提供了对象的地址,这不一定是第一个成员的地址.唯一的例外是所谓的标准布局类型.从C11标准:(9.2/20)Apointe

  5. c – 编译单元之间共享的全局const对象

    当我声明并初始化一个const对象时.两个cpp文件包含此标头.和当我构建解决方案时,没有链接错误,你会得到什么如果g_Const是一个非const基本类型!PrintInUnit1()和PrintInUnit2()表明在两个编译单元中有两个独立的“g_Const”具有不同的地址,为什么?

  6. 什么是C名称查找在这里? (&amp;GCC对吗?)

    为什么在第三个变体找到func,但是在实例化的时候,原始变体中不合格查找找不到func?解决方法一般规则是,任何不在模板定义上下文中的内容只能通过ADL来获取.换句话说,正常的不合格查找仅在模板定义上下文中执行.因为在定义中间语句时没有声明func,并且func不在与ns::type相关联的命名空间中,所以代码形式不正确.

  7. c – 在输出参数中使用auto

    有没有办法在这种情况下使用auto关键字:当然,不可能知道什么类型的.因此,解决方案应该是以某种方式将它们合并为一个句子.这可用吗?解决方法看起来您希望默认初始化给定函数期望作为参数的类型的对象.您无法使用auto执行此操作,但您可以编写一个特征来提取函数所需的类型,然后使用它来声明您的变量:然后你就像这样使用它:当然,只要你重载函数,这一切都会失败.

  8. 在C中说“推动一切浮动”的确定性方式

    鉴于我更喜欢将程序中的数字保留为int或任何内容,那么使用这些数字的浮点数等效的任意算术最方便的方法是什么?说,我有我想写通过将转换放在解析的运算符树叶中,无需将表达式转化为混乱是否可以使用C风格的宏?应该用新的类和重载操作符完成吗?解决方法这是一个非常复杂的表达.更好地给它一个名字:现在当您使用整数参数调用它时,由于参数的类型为double,因此使用常规的算术转换将参数转换为double用C11lambda……

  9. objective-c – 如何获取未知大小的NSArray的第一个X元素?

    在objectiveC中,我有一个NSArray,我们称之为NSArray*largeArray,我想要获得一个新的NSArray*smallArray,只有第一个x对象…

  10. c – Setprecision是混乱

    我只是想问一下setprecision,因为我有点困惑.这里是代码:其中x=以下:方程的左边是x的值.1.105=1.10应为1.111.115=1.11应为1.121.125=1.12应为1.131.135=1.14是正确的1.145=1.15也正确但如果x是:2.115=2.12是正确的2.125=2.12应为2.13所以为什么在一定的价值是正确的,但有时是错误的?请启发我谢谢解决方法没有理由期望使用浮点系统可以正确地表示您的帖子中的任何常量.因此,一旦将它们存储在一个双变量中,那么你所拥有的确切的一

返回
顶部