hashtable
- 有N个元素,这些元素要放到容器中,且每个元素都可以转化为一个数值。这些元素的个数变化范围是0~2的32次方-1,需要至少2的32次方个元素的大小
- 由于不可能准备这么大的空间,且元素的个数也不一定到2的32次方。对每个元素编号,采用取余法确定元素要放置的地点,如果容器长度为H,元素的编号为M,则将它放置到M%H处
- 如果当前位置已经有元素了,则发生了冲突,将它跟在当前元素的后面(采用链表)
- 如果一个节点的链表太长,就要将该链表打散重排。经验法则是,当元素个数大于篮子的个数,就要将链表打散。即将原来的篮子数扩容为原来的2倍附近的质数,再重新计算每个元素该放置的位置。
- 篮子的起始数量一般为质数。
template<class Value, class Key, class HashFcn, class ExtractKey, class EqualKey, class Alloc = alloc>
class hashtable{
public:
typedef HashFcn hasher;
typedef EqualKey key_equal;
typedef size_t size_type;
private:
hasher hash;
key_equal equals;
ExtractKey get_key;
typedef __hashtable_node<Value> node;
vector<node*, Alloc> buckets;
size_type num_elements;
public:
size_type bucket_count() const { return bucket.size(); }
...
};
- hashtable的大小为19,对齐后是20个字节
- 函数对象的大小理论上是0,实际上是1,三个函数对象大小就是3
- vector变量buckets大小是12,有三个指针
- size_type类型的大小是4
template<class Value>
struct __hashtable_node{
__hashtable_node* next;
Value val;
};
- 迭代器
- cur指向的是某个元素,ht指向的是哈希表本身,即bucket
- 迭代器要实现走到当前链表尾时可以重新回到bucket处
template<class Value, class Key, class HashFcn, class ExtractKey, class EqualKey, class Alloc>
struct __hashtable_iterator{
...
node* cur;
hashtable* ht;
};
struct eqstr{
bool operator() (const char* s1, const char* s2) const
{ return strcmp(s1, s2)==0; }
};
hashtable<const char*, const char*, hash<const char*>, identity<const char*>, eqstr, alloc>
ht(50, hash<const char*>(), equstr());
ht.insert_unique("kiwi");
ht.insert_unique("plum"):
ht.insert_unique("apple");
- 哈希函数的目的,就是根据元素值算出一个hash code,使得元素经 hash code映射之后能够足够随机的被放置在哈希表中。越是随机,越不容易发生碰撞。
template <class Key> struct hash { };
__STL_TEMPLATE_NULL struct hash<char>{
size_t operator() (char x) const { return x; }
};
__STL_TEMPLATE_NULL struct hash<short>{
size_t operator() (short x) const { return x; }
};
...
inline size_t __stl_hash_string(const char* s)
{
unsigned long h = 0;
for(; *s; ++s)
h = 5 * h + *s;
return size_t(h);
}
__STL_TEMPLATE_NULL struct hash<char*>
{
size_t operator()(const char* s) const { return __stl_hash_string(s); }
};
__STL_TEMPLATE_NULL struct hash<const char*>
{
size_t operator()(const char* s) const { return __stl_hash_string(s); }
};
G4.9模板参数
template<typename T, typename Hash = hash<T>, typename EqPred = equal_to<T>, typename Allocator = allocator<T>>
class unordered_set;
template<typename T, typename Hash = hash<T>, typename EqPred = equal_to<T>, typename Allocator = allocator<T>>
class unordered_multiset;
template<typename Key, typename T, typename Hash = hash<T>, typename EqPred = equal_to<T>, typename Allocator = allocator<pair<const Key, T>>>
class unordered_map;
template<typename Key, typename T, typename Hash = hash<T>, typename EqPred = equal_to<T>, typename Allocator = allocator<pair<Kry, T>>>
class unordered_multimap;