【免责声明】本人乃才疏学浅之辈,此抛砖引玉之举;若有纰漏错误之处,望不吝指正。
【原文链接】C++11: unordered maps By Ernesto Bascón Pantoja's blog
【内容提要】
1、unordered maps简介
2、unordered_map实例化时,传参的两种方式
【正文】
C++ STL提供了一个有序map关联容器(模板类),其内部实现是一种高效的平衡二叉树;这种实现的优点是检索效率高(平均时间复杂度O(log2N),N表示map中元素个数),并且按照已经排列好的次序遍历map容器查找元素。
C++11增加了一种无序map容器,其内部实现是哈希表。这种实现的显著优点是访问容器中任意元素时间复杂度为常量级(O(1)),但其明显的不足是容器中的元素无序且需要更大的内存空间(与map相比)。
The API of both kind of maps is quite similar; for example, look at this code:
上述 两种map容器的API非常相似,如下列示例代码所示:
#include
#include
#include
上面程序代码输出如下:
four; 4
one; 1
three; 3
two; 2
*******************
one; 1
three; 3
two; 2
four; 4
如你所见:
两种容器创建和操作使用的方式完全一致。
unordered_map容器的输出是无序的。
如果只是使用STL提供的基本类型(int ,char,long,short,etc)和strings,一切都很美好(STL已经提供默认的hash code和compare函数)。一旦我们想使用自定义的数据类型:类(class)或结构体(struct)时,使用unordered_map就不太舒适了。
我们知道,在JAVA中,如果类要作为容器的键(Key),需要重写(override)类的equals 和hashCode方法,否则代码能正常编译,却难如期工作。(假设你已经有java知识)
在C++中,我们也需要做类似的事情,比如,1、需要实现一个函数对象hash(function object,对应于下面代码片段中的hash参数)用于生成哈希值(hash code),2、同时需要实现一个函数对象equal_to(对应于下面代码中的equal_to参数)用于比较自定义类或结构体的两个对象,3、实例化unordered map容器时,传入前两步构造的函数对象作为模板参数。具体代码如下:
template , typename EQUAL = equal_to >
class unordered_map
{ ..... };
实例化unordered map容器时,需要实现的hash函数对象的模板如下代码所示:
template
class hash
{
public:
long operator()(const T& o) const { return 0; }
};
and provides specializations for all the primitive types and for the std::string class.
The equal_to
class template is implemented similar to this:
template
class equal_to
{
public:
bool operator()(const T& a, const T& b) const { return a == b; }
};
因此,如果我们勇于KEY的自定义类或结构体重写了operator==操作符,我们可以不需提供EQUAL模板参数(equal_to函数对象)。
现以自定义结构体(struct article_id)和自定义类(class article)为例,实现如下:
struct article_id
{
string brand;
int id;
article_id(const string& b, int id) : brand(b), id(id) { }
};
ostream& operator<<(ostream& os, const article_id& a)
{
return os << "(" << a.brand << ") " << a.id;
}
class article
{
string brand, model, description;
public:
article(const string& b, const string& m, const string& d)
: brand(b), model(m), description(d) { }
const string& get_brand() const { return brand; }
const string& get_model() const { return model; }
const string& get_description() const { return description; }
};
ostream& operator<<(ostream& os, const article& a)
{
return os << "Brand: " << a.get_brand() << "; Model: " << a.get_model()
<< "; Description: " << a.get_description();
}
如果用unordered map存储,用自定义结构体(article_id)为Key,自定义类article的实例为值(
)键值对,我们需要做如下工作,1、实现hash函数对象,2、实现equal _to函数对象,代码如下:
class article_hash
{
public:
long operator()(const article_id& x) const
{
hash z;
return z(x.brand) * 100 + x.id;
}
};
class article_equal_to
{
public:
bool operator()(const article_id& a, const article_id& b) const
{
return a.brand == b.brand && a.id == b.id;
}
};
定义了hash和equal_to函数对象后,我们就可以用自定义结构体article_id做unordered map函数的Key.代码如下:
int main()
{
unordered_map x;
x.insert(make_pair(article_id("acme", 1), article("acme", "tv", "Acme TV")));
x.insert(make_pair(article_id("foo", 4), article("foo", "phone", "fooPhone")));
show(x);
return 0;
}
到此,我们了解了实例化unordered map容器的第一种传参方式,即实例化容器时,显示传入自己实现的函数对象(hash equal_to )模板参数;
另外一种更成熟的方式是,用自定义结构体或类的article_hash and article_equal_to 函数对象,“重写“(specializations) 命名空间std中的hash和equal_to模板。
namespace std
{
template <>
class hash
{
public:
long operator()(const article_id& x) const
{
hash z;
return z(x.brand) * 100 + x.id;
}
};
template <>
class equal_to
{
public:
bool operator()(const article_id& a, const article_id& b) const
{
return a.brand == b.brand && a.id == b.id;
}
};
}
当我们用第二种方式,重写(特化(specializations))命名空间std中的hash和equal_to 模板后,实例化 unordered map容器时,就无需显示传入参数3,与参数4(typename HASH =hash ,typename EQUAL=equal_to )
int main()
{
unordered_map x;
x.insert(make_pair(article_id("acme", 1), article("acme", "tv", "Acme TV")));
x.insert(make_pair(article_id("foo", 4), article("foo", "phone", "fooPhone")));
show(x);
return 0;
}
REALLY COOL.OVER:).
更多链接:
http://cpptutorials.freeforums.org/tr1-unordered-map-t621.html
http://stackoverflow.com/questions/15595804/c-hash-function-for-string-in-unordered-map
http://stackoverflow.com/questions/15601568/need-example-of-stdunordered-map-constructor