STL hash table, Unordered Contain
C++11加入使用hash table实现的Unordered Containers。容器中元素是不排序的,同时我们也不能指定某个元素的位置。
头文件:#include <unordered_set> unordered_set; unordered_multiset;
#include <unordered_map> unordered_map; unordered_multimap;
操作基本类似于关联容器,只是底层使用hash table。主要不同是理解bucket的概念。
namespace std {
template <typename T,
typaname Hash = hash<T>,
typename EqPred = equal_to<T>,
typename Allocator = allocator<T> >
class unordered_set;
template <typename Key, typename T,
typanem Hash = hash<T>,
typename EqPred = equal_to<T>,
typanema Allocator = allocator<pair<const Key, T> > >
class unordered_ma;
}注意点:
(1) hash函数为hash<T>
(2) 比较准则 equal_to<T>
1.特点
标准没有指定实现,vs和g++都使用开链法实现。
指定迭代器至少为forward_iterator,但是具体实现一般都是forward_iterator。
插入,删除,查找元素保证分摊的常数时间。rehashing可能发生,这是一个线性复杂度的操作。
相对于普通关联容器的不利:
(1) 不提供<, >, <=,>=去排序元素,since c++11提供了==, !=。
(2)不提供lower_bound(), upper_bound()
(3) 不提供反向迭代器,forward_iterator
(4)不能直接访问元素
(5) 可以通过iterator访问元素,key值是const。
(6) 可以指定min 桶数。
(7) 可以提供自定义的hash function。
(8)可以指定查找元素时的相等准则。重载operator=。
(9) 可以指定max 负载因子,当超过时可以自动重排。
(9) 可以强制rehashing。
rehashing发生的时机:只有在insert(), rehash(), reserve(), clear()之后才可能。
这保证了erase()从来都不会使iterator,reference,和指针失效。
因此,当你删除很多元素是,桶的大小不会改变。但是当你insert()一个元素时,桶的大小可能压缩(rehash)。
相等key是相邻的,rehashing时保证key的相对顺序不变。
2.构造,复制,赋值
unordered c([bnum], [hf], [cmp]); //桶数目,hash function, 比较谓词都是可选
unordered c(beg, end, [bnum][hf][cmp]);
unordered c = initlist;
unordered c(initlist);
复制和移动复制
c.~Unord();
主要的特点是可以指定:bucket num,hash function, cmp
3.容器内部布局的操作
c.hash_function()
c.key_eq()
c.bucket(val): 返回val所在的桶的索引
c.bucket_count():返回桶的数目,size()返回所有元素的数目。
c.size():返回元素的数目
c.bucket_size(buckidx): 返回桶buckidx的元素数目
c.[c]begin(buckdx):返回桶buckdx的第一个元素forward iter
c.[c]end(buckdx):返回桶buckdx的最后一个元素之后位置
c.max_bucket_count(): 最大桶的数目
c.load_factor():返回当前的负载因子,0.7..0.8之间速度和内存消耗是最平均的。
c.max_load_factor:返回当前最大负载因此,<=1。
c.max_load_factor(val):设置最大负载因子为val,当当前的负载因子 > val时rehashing。若是比较关心速度,可以设置这个。
c.rehashi(bnum); 再散列容器,桶的大小至少为bnum。但是还要考虑到此时的负载因子, 可以存的元素数量为 load_factor * bunm <= bnum; 当前元素数量可能大于此值,可能会进一步的再散列。
c.reserve(num);再散列容器,元素数量至少为num。已考虑了负载因子,能够至少存num个元素而不会再散列。桶的数量为num / load_factor。保证可以存下num元素而不会再散列。
4. 定义自己的hash function
hash function映射元素的值到一个指定的桶,自定义hash function只需映射不同元素值相等的分布在[0, size_t)。
#include <functional>
class customer
{
…
}class CustomerHash
{
public:
std::size_t operator() (const Customer &c) const
{
return…
}}
std::unordered_set<Customer, CustomerHash> custset;
也可以使用函数:
std::size_t customer_hash_func(const Customer &c)
{
return …
}std::unordered_set<Customer, std:size_t(*)(const Customer&)>
custset(20, customer_hash_func);
对于hash_val的选择:
可以使用boost的hash_combine()。
5.定义自己的Equivalence Criterion
可以作为我们查找值的相等准则,默认使用equal_to()使用operator==比较元素。
可以使用普通函数或者函数对象。
注意:带着非默认相等谓词的unordered 容器通常也需要一个非默认的hash function。
6. 查找
主要在快速查找时用
c.count(val);
c.find(val);
c.equal_range(val);