您的位置:首页 > 编程语言 > C语言/C++

c++STL中的hash_map自定义类。

2016-01-26 01:18 357 查看
是的,hash_map是一个很方便的容器,有了STL确确实实给了C++developer很大方便,hash_map就是其中一种。他在数据少的时候,作用和基于RB-tree的map差不多,甚至不如,毕竟有hasher。但是在大量数据的时候,就很快捷了。我平时用hash_map都是用基本类型的,最多弄个string类,也是库里已经弄好了的。直接套模板就行。可是今天遇到一个问题就是当你需要把一个自定义类作为key的时候,应该怎么办?当我写完程序并编译的时候,他报错了,报了很长的一段错。前两行是这样的:

error C2784: “bool std::operator <(const std::list<_Ty,_Alloc> &,const std::list<_Ty,_Alloc> &)”: 未能从“const Box”为“const std::list<_Ty,_Alloc> &”推导 模板 参数

e:\program files\vc\include\list(1958) : 参见“std::operator <”的声明

然后我根本不知道这是什么问题,只好百度,百度里基本说到都是忘记使用#include<string>,然而这并不是问题的关键,因为我并没有用到字符串啊,就是加上也是一样报错。

终于我耗时1h才找到只言片语,又回头看看错误报告,似乎是<的原因?没有重载?是了,因为hash_map实现的时候需要用less也就是<函数来对key排序,那就把<重载了

bool operator<(const Box &k2)const
{
if ((*this).width != k2.width)
{
return (*this).width < k2.width;
}

if ((*this).depth != k2.depth)
{
return (*this).depth < k2.depth;
}
if ((*this).height != k2.height)
{
return (*this).height < k2.height;
}
return false;
}

那么应该可以了吧?结果还是报错:

1>e:\program files\vc\include\xhash(30): error C2440: “类型转换”: 无法从“const Box”转换为“size_t”

1>          没有可用于执行该转换的用户定义的转换运算符,或者无法调用该运算符

那么是跟size_t有关喽,又用了1h我终于知道问题所在了,http://www.cplusplus.com/中的定义是这样的



然后详细情况如下:



是的少了个hasher,在《STL源码剖析》中,阐明了只有基本类型和字符指针可以调用默认hash函数。在使用了其他类型时(比如自定义类)用户必须为其自定义一个hash函数像这样:size_t operator() (const Box& b)const放在一个结构体中,作为仿函数,也就是函数对象。

我个人在这是这样实现hasher的:

size_t operator() (const Box& b)const

{

return (b.depth + 10 * b.height + 100 * b.width) % 20;

};

本来以为总算可以了,然后还是报错:1>e:\program files\vc\include\xhash(264): error C2039: “bucket_size”: 不是“cmp_key”的成员

1>          c:\users\administrator\documents\visual studio 2013\projects\最高的箱子\最高的箱子\源.cpp(47) : 参见“cmp_key”的声明

是的,真烦,bucket_size是什么鬼啊,继续查资料。。。

终于,我找到了,在http://www.cplusplus.com/中的定义是这样的:



虽然是unordered_map不过定义应该差不多吧。而在stackoverflow中,大神是这么说的:





在《STL源码剖析》中,是这么说buckets的:hashTable表格内的元素为桶子(bucket),就是说表格内的每个单元,涵盖的不只是个节点,甚至可能是一“桶”节点。

这就很明了了,我们可以在结果中加上:

enum
{   //   parameters   for   hash   table   
bucket_size = 4,   //   0   <   bucket_size   
min_buckets = 8  //   min_buckets   =   2   ^^   N,   0   <   N   
};

必不可少的。然而还是报错:

1>e:\program files\vc\include\xhash(744): error C2064: 项不会计算为接受 2 个参数的函数

1>          类不会将“operator()”或用户定义的转换运算符定义到指向函数的指针或指向函数的引用(它们接受适当数量的参数)

恩,重载<在此时来说是不行的,需要在结构体中加上:

bool operator()(const Box &k1, const Box &k2)const
{
if (k1.width != k2.width)
{
return k1.width < k2.width;
}

if (k1.depth != k2.depth)
{
return k1.depth < k2.depth;
}
if (k1.height != k2.height)
{
return k1.height < k2.height;
}
return false;
}

依然是仿函数,而不是重载运算符作为equalToKey()。这样就全部完成了,全部代码在这:http://blog.csdn.net/youngstunner/article/details/50583852

完整的实现了一个自定义类的hash_map,大功告成!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息