hashtable

  • 散列表,常数平均时间表现。可被视为一种字典结构。

  • 空间换时间:

  • 上述解决方法始终导致array太大,因此创建hash function,限制TableSize。

  • 解决碰撞

    • 线性探测:负载系数(元素个数/表格大小:限制在0-1之间)。

      • 目标空间被占用则向下寻找(尾部连着头部)直到空格或符合者
      • 惰性删除:只能标记删除
      • 平均插入成本的成长幅度远高于负载系数的成长幅度:主集团primary clustering
    • 二次探测:一般更改为+ -,而不仅仅是+

      • 假设表格大小为质数保持负载系数0.5以下,就可以确定插入新元素所需探测数不多于2
      • 节省方法:用上一个H值计算现在的H值,并结合位移位,并省略一些mod运算
      • 消除主集团却可能造成次集团
    • 开链:每个表格元素维护一个list。是hash_table使用方法,这里的list并不是STL内部建立的list,而是hash table node。聚合体以vector完成

  • hashtable没有后退operator–操作,即没有逆向迭代器

  • resize操作在拆每个list并重建时用到了头插入的方法,需要阅读源码

  • bkt_num是判断落在哪个bucket中的函数,将hash_function包装了一下,因为如果是字符或字符串型,是需要转换的。

  • 整体拷贝和删除时要特别注意内存的释放问题

  • 客户端调用非常麻烦



  • 注意hash_function在另一个单独的文件夹中,特别针对char,int,long等字符型(利用Acs码)。double,float,string型无法处理,需要用户自定义

    inline size_t __stl_hash_string(const char* s)
    {unsigned long h = 0; for ( ; *s; ++s)//s是指针型,加一就是右移,h = 5*h + *s;return size_t(h);
    }
    
#ifndef __SGI_STL_INTERNAL_HASHTABLE_H
#define __SGI_STL_INTERNAL_HASHTABLE_H#include <stl_algobase.h>
#include <stl_alloc.h>
#include <stl_construct.h>
#include <stl_tempbuf.h>
#include <stl_algo.h>
#include <stl_uninitialized.h>
#include <stl_function.h>
#include <stl_vector.h>
#include <stl_hash_fun.h>__STL_BEGIN_NAMESPACE//结点
template <class Value>
struct __hashtable_node
{__hashtable_node* next;Value val;
};  template <class Value, class Key, class HashFcn,class ExtractKey, class EqualKey, class Alloc = alloc>
class hashtable;//迭代器定义
template <class Value, class Key, class HashFcn,class ExtractKey, class EqualKey, class Alloc>
struct __hashtable_iterator;template <class Value, class Key, class HashFcn,class ExtractKey, class EqualKey, class Alloc>
struct __hashtable_const_iterator;template <class Value, class Key, class HashFcn,class ExtractKey, class EqualKey, class Alloc>
struct __hashtable_iterator {typedef hashtable<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>hashtable;typedef __hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>iterator;typedef __hashtable_const_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>const_iterator;typedef __hashtable_node<Value> node;typedef forward_iterator_tag iterator_category;typedef Value value_type;typedef ptrdiff_t difference_type;typedef size_t size_type;typedef Value& reference;typedef Value* pointer;node* cur;//迭代器目前所指结点hashtable* ht;//保持对容器的连结关系__hashtable_iterator(node* n, hashtable* tab) : cur(n), ht(tab) {}__hashtable_iterator() {}reference operator*() const { return cur->val; }
#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */iterator& operator++();iterator operator++(int);bool operator==(const iterator& it) const { return cur == it.cur; }bool operator!=(const iterator& it) const { return cur != it.cur; }
};template <class Value, class Key, class HashFcn,class ExtractKey, class EqualKey, class Alloc>
struct __hashtable_const_iterator {typedef hashtable<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>hashtable;typedef __hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>iterator;typedef __hashtable_const_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>const_iterator;typedef __hashtable_node<Value> node;typedef forward_iterator_tag iterator_category;typedef Value value_type;typedef ptrdiff_t difference_type;typedef size_t size_type;typedef const Value& reference;typedef const Value* pointer;const node* cur;const hashtable* ht;__hashtable_const_iterator(const node* n, const hashtable* tab): cur(n), ht(tab) {}__hashtable_const_iterator() {}__hashtable_const_iterator(const iterator& it) : cur(it.cur), ht(it.ht) {}reference operator*() const { return cur->val; }
#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */const_iterator& operator++();const_iterator operator++(int);bool operator==(const const_iterator& it) const { return cur == it.cur; }bool operator!=(const const_iterator& it) const { return cur != it.cur; }
};// Note: assumes long is at least 32 bits.
//以质数设计表格大小
static const int __stl_num_primes = 28;
static const unsigned long __stl_prime_list[__stl_num_primes] =
{53,         97,           193,         389,       769,1543,       3079,         6151,        12289,     24593,49157,      98317,        196613,      393241,    786433,1572869,    3145739,      6291469,     12582917,  25165843,50331653,   100663319,    201326611,   402653189, 805306457, 1610612741, 3221225473ul, 4294967291ul
};//找出上述28个质数中,最接近并大于n的那个质数
inline unsigned long __stl_next_prime(unsigned long n)
{const unsigned long* first = __stl_prime_list;const unsigned long* last = __stl_prime_list + __stl_num_primes;const unsigned long* pos = lower_bound(first, last, n);return pos == last ? *(last - 1) : *pos;
}template <class Value, class Key, class HashFcn,class ExtractKey, class EqualKey,class Alloc>
class hashtable {
public:typedef Key key_type;typedef Value value_type;typedef HashFcn hasher; //为template型别参数重新定义一个名称typedef EqualKey key_equal; //为template型别参数重新定义一个名称typedef size_t            size_type;typedef ptrdiff_t         difference_type;typedef value_type*       pointer;typedef const value_type* const_pointer;typedef value_type&       reference;typedef const value_type& const_reference;hasher hash_funct() const { return hash; }key_equal key_eq() const { return equals; }private:hasher hash;//hash function 的函数型别key_equal equals;//判断键值是否相同ExtractKey get_key;//从节点中取出键值的方法typedef __hashtable_node<Value> node;typedef simple_alloc<node, Alloc> node_allocator;vector<node*,Alloc> buckets; //注意:以vector完成,且是指针类型size_type num_elements;//public:typedef __hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>iterator;typedef __hashtable_const_iterator<Value, Key, HashFcn, ExtractKey, EqualKey,Alloc>const_iterator;friend struct__hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>;friend struct__hashtable_const_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>;public:hashtable(size_type n,const HashFcn&    hf,const EqualKey&   eql,const ExtractKey& ext): hash(hf), equals(eql), get_key(ext), num_elements(0){initialize_buckets(n);}hashtable(size_type n,const HashFcn&    hf,const EqualKey&   eql): hash(hf), equals(eql), get_key(ExtractKey()), num_elements(0){initialize_buckets(n);}hashtable(const hashtable& ht): hash(ht.hash), equals(ht.equals), get_key(ht.get_key), num_elements(0){copy_from(ht);}hashtable& operator= (const hashtable& ht){if (&ht != this) {clear();hash = ht.hash;equals = ht.equals;get_key = ht.get_key;copy_from(ht);}return *this;}~hashtable() { clear(); }size_type size() const { return num_elements; }size_type max_size() const { return size_type(-1); }bool empty() const { return size() == 0; }void swap(hashtable& ht){__STD::swap(hash, ht.hash);__STD::swap(equals, ht.equals);__STD::swap(get_key, ht.get_key);buckets.swap(ht.buckets);__STD::swap(num_elements, ht.num_elements);}iterator begin(){ for (size_type n = 0; n < buckets.size(); ++n)if (buckets[n])return iterator(buckets[n], this);return end();}iterator end() { return iterator(0, this); }const_iterator begin() const{for (size_type n = 0; n < buckets.size(); ++n)if (buckets[n])return const_iterator(buckets[n], this);return end();}const_iterator end() const { return const_iterator(0, this); }friend booloperator== __STL_NULL_TMPL_ARGS (const hashtable&, const hashtable&);public:size_type bucket_count() const { return buckets.size(); }//最大可以为多少,将为4294967291size_type max_bucket_count() const{ return __stl_prime_list[__stl_num_primes - 1]; } size_type elems_in_bucket(size_type bucket) const{size_type result = 0;for (node* cur = buckets[bucket]; cur; cur = cur->next)result += 1;return result;}pair<iterator, bool> insert_unique(const value_type& obj){resize(num_elements + 1);//判断是否需要重建表格,需要则扩充return insert_unique_noresize(obj);}//允许重复,需要就扩充iterator insert_equal(const value_type& obj){resize(num_elements + 1);return insert_equal_noresize(obj);}pair<iterator, bool> insert_unique_noresize(const value_type& obj);iterator insert_equal_noresize(const value_type& obj);#ifdef __STL_MEMBER_TEMPLATEStemplate <class InputIterator>void insert_unique(InputIterator f, InputIterator l){insert_unique(f, l, iterator_category(f));}template <class InputIterator>void insert_equal(InputIterator f, InputIterator l){insert_equal(f, l, iterator_category(f));}template <class InputIterator>void insert_unique(InputIterator f, InputIterator l,input_iterator_tag){for ( ; f != l; ++f)insert_unique(*f);}template <class InputIterator>void insert_equal(InputIterator f, InputIterator l,input_iterator_tag){for ( ; f != l; ++f)insert_equal(*f);}template <class ForwardIterator>void insert_unique(ForwardIterator f, ForwardIterator l,forward_iterator_tag){size_type n = 0;distance(f, l, n);resize(num_elements + n);for ( ; n > 0; --n, ++f)insert_unique_noresize(*f);}template <class ForwardIterator>void insert_equal(ForwardIterator f, ForwardIterator l,forward_iterator_tag){size_type n = 0;distance(f, l, n);resize(num_elements + n);for ( ; n > 0; --n, ++f)insert_equal_noresize(*f);}#else /* __STL_MEMBER_TEMPLATES */void insert_unique(const value_type* f, const value_type* l){size_type n = l - f;resize(num_elements + n);for ( ; n > 0; --n, ++f)insert_unique_noresize(*f);}void insert_equal(const value_type* f, const value_type* l){size_type n = l - f;resize(num_elements + n);for ( ; n > 0; --n, ++f)insert_equal_noresize(*f);}void insert_unique(const_iterator f, const_iterator l){size_type n = 0;distance(f, l, n);resize(num_elements + n);for ( ; n > 0; --n, ++f)insert_unique_noresize(*f);}void insert_equal(const_iterator f, const_iterator l){size_type n = 0;distance(f, l, n);resize(num_elements + n);for ( ; n > 0; --n, ++f)insert_equal_noresize(*f);}
#endif /*__STL_MEMBER_TEMPLATES */reference find_or_insert(const value_type& obj);iterator find(const key_type& key) {size_type n = bkt_num_key(key);node* first;for ( first = buckets[n];first && !equals(get_key(first->val), key);first = first->next){}return iterator(first, this);} const_iterator find(const key_type& key) const{size_type n = bkt_num_key(key);const node* first;for ( first = buckets[n];first && !equals(get_key(first->val), key);first = first->next){}return const_iterator(first, this);} size_type count(const key_type& key) const{const size_type n = bkt_num_key(key);size_type result = 0;for (const node* cur = buckets[n]; cur; cur = cur->next)if (equals(get_key(cur->val), key))++result;return result;}pair<iterator, iterator> equal_range(const key_type& key);pair<const_iterator, const_iterator> equal_range(const key_type& key) const;size_type erase(const key_type& key);void erase(const iterator& it);void erase(iterator first, iterator last);void erase(const const_iterator& it);void erase(const_iterator first, const_iterator last);void resize(size_type num_elements_hint);void clear();private:size_type next_size(size_type n) const { return __stl_next_prime(n); }void initialize_buckets(size_type n){//举例:传入50会返回53,首先保留53个空间,然后将其全部填入0const size_type n_buckets = next_size(n);buckets.reserve(n_buckets);buckets.insert(buckets.end(), n_buckets, (node*) 0);num_elements = 0;}size_type bkt_num_key(const key_type& key) const{return bkt_num_key(key, buckets.size());}size_type bkt_num(const value_type& obj) const{return bkt_num_key(get_key(obj));}size_type bkt_num_key(const key_type& key, size_t n) const{return hash(key) % n;}size_type bkt_num(const value_type& obj, size_t n) const{return bkt_num_key(get_key(obj), n);}node* new_node(const value_type& obj){node* n = node_allocator::allocate();n->next = 0;__STL_TRY {construct(&n->val, obj);return n;}__STL_UNWIND(node_allocator::deallocate(n));}void delete_node(node* n){destroy(&n->val);node_allocator::deallocate(n);}void erase_bucket(const size_type n, node* first, node* last);void erase_bucket(const size_type n, node* last);void copy_from(const hashtable& ht);};//没有--!
template <class V, class K, class HF, class ExK, class EqK, class A>
__hashtable_iterator<V, K, HF, ExK, EqK, A>&
__hashtable_iterator<V, K, HF, ExK, EqK, A>::operator++()
{const node* old = cur;cur = cur->next;//找出下一个元素if (!cur) {//如果正好是尾端,跳到下一个bucket身上(下一个list头部)size_type bucket = ht->bkt_num(old->val);while (!cur && ++bucket < ht->buckets.size())//不超出bucket范围cur = ht->buckets[bucket];}return *this;
}template <class V, class K, class HF, class ExK, class EqK, class A>
inline __hashtable_iterator<V, K, HF, ExK, EqK, A>
__hashtable_iterator<V, K, HF, ExK, EqK, A>::operator++(int)
{iterator tmp = *this;++*this;return tmp;//注意:++i和i++的区别是,前者返回加之后,后者返回原值
}template <class V, class K, class HF, class ExK, class EqK, class A>
__hashtable_const_iterator<V, K, HF, ExK, EqK, A>&
__hashtable_const_iterator<V, K, HF, ExK, EqK, A>::operator++()
{const node* old = cur;cur = cur->next;if (!cur) {size_type bucket = ht->bkt_num(old->val);while (!cur && ++bucket < ht->buckets.size())cur = ht->buckets[bucket];}return *this;
}template <class V, class K, class HF, class ExK, class EqK, class A>
inline __hashtable_const_iterator<V, K, HF, ExK, EqK, A>
__hashtable_const_iterator<V, K, HF, ExK, EqK, A>::operator++(int)
{const_iterator tmp = *this;++*this;return tmp;
}#ifndef __STL_CLASS_PARTIAL_SPECIALIZATIONtemplate <class V, class K, class HF, class ExK, class EqK, class All>
inline forward_iterator_tag
iterator_category(const __hashtable_iterator<V, K, HF, ExK, EqK, All>&)
{return forward_iterator_tag();
}template <class V, class K, class HF, class ExK, class EqK, class All>
inline V* value_type(const __hashtable_iterator<V, K, HF, ExK, EqK, All>&)
{return (V*) 0;
}template <class V, class K, class HF, class ExK, class EqK, class All>
inline hashtable<V, K, HF, ExK, EqK, All>::difference_type*
distance_type(const __hashtable_iterator<V, K, HF, ExK, EqK, All>&)
{return (hashtable<V, K, HF, ExK, EqK, All>::difference_type*) 0;
}template <class V, class K, class HF, class ExK, class EqK, class All>
inline forward_iterator_tag
iterator_category(const __hashtable_const_iterator<V, K, HF, ExK, EqK, All>&)
{return forward_iterator_tag();
}template <class V, class K, class HF, class ExK, class EqK, class All>
inline V*
value_type(const __hashtable_const_iterator<V, K, HF, ExK, EqK, All>&)
{return (V*) 0;
}template <class V, class K, class HF, class ExK, class EqK, class All>
inline hashtable<V, K, HF, ExK, EqK, All>::difference_type*
distance_type(const __hashtable_const_iterator<V, K, HF, ExK, EqK, All>&)
{return (hashtable<V, K, HF, ExK, EqK, All>::difference_type*) 0;
}#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */template <class V, class K, class HF, class Ex, class Eq, class A>
bool operator==(const hashtable<V, K, HF, Ex, Eq, A>& ht1,const hashtable<V, K, HF, Ex, Eq, A>& ht2)
{typedef typename hashtable<V, K, HF, Ex, Eq, A>::node node;if (ht1.buckets.size() != ht2.buckets.size())return false;for (int n = 0; n < ht1.buckets.size(); ++n) {node* cur1 = ht1.buckets[n];node* cur2 = ht2.buckets[n];for ( ; cur1 && cur2 && cur1->val == cur2->val;cur1 = cur1->next, cur2 = cur2->next){}if (cur1 || cur2)return false;}return true;
}  #ifdef __STL_FUNCTION_TMPL_PARTIAL_ORDERtemplate <class Val, class Key, class HF, class Extract, class EqKey, class A>
inline void swap(hashtable<Val, Key, HF, Extract, EqKey, A>& ht1,hashtable<Val, Key, HF, Extract, EqKey, A>& ht2) {ht1.swap(ht2);
}#endif /* __STL_FUNCTION_TMPL_PARTIAL_ORDER *///不需要重建的情况下插入新节点,不允许重复
template <class V, class K, class HF, class Ex, class Eq, class A>
pair<typename hashtable<V, K, HF, Ex, Eq, A>::iterator, bool>
hashtable<V, K, HF, Ex, Eq, A>::insert_unique_noresize(const value_type& obj)
{const size_type n = bkt_num(obj);//obj对应于 #n bucketnode* first = buckets[n];//串行头部for (node* cur = first; cur; cur = cur->next) //走完整个列表if (equals(get_key(cur->val), get_key(obj)))return pair<iterator, bool>(iterator(cur, this), false);node* tmp = new_node(obj);//产生新节点tmp->next = first;//头插入buckets[n] = tmp;++num_elements;return pair<iterator, bool>(iterator(tmp, this), true);
}//不重建下插入新节点,允许重复
template <class V, class K, class HF, class Ex, class Eq, class A>
typename hashtable<V, K, HF, Ex, Eq, A>::iterator
hashtable<V, K, HF, Ex, Eq, A>::insert_equal_noresize(const value_type& obj)
{const size_type n = bkt_num(obj);node* first = buckets[n];
//遍历,遇到相同键值就在那里插入for (node* cur = first; cur; cur = cur->next) if (equals(get_key(cur->val), get_key(obj))) {node* tmp = new_node(obj);tmp->next = cur->next;cur->next = tmp;++num_elements;return iterator(tmp, this);}
//否则头插入node* tmp = new_node(obj);tmp->next = first;buckets[n] = tmp;++num_elements;return iterator(tmp, this);
}template <class V, class K, class HF, class Ex, class Eq, class A>
typename hashtable<V, K, HF, Ex, Eq, A>::reference
hashtable<V, K, HF, Ex, Eq, A>::find_or_insert(const value_type& obj)
{resize(num_elements + 1);size_type n = bkt_num(obj);node* first = buckets[n];for (node* cur = first; cur; cur = cur->next)if (equals(get_key(cur->val), get_key(obj)))return cur->val;node* tmp = new_node(obj);tmp->next = first;buckets[n] = tmp;++num_elements;return tmp->val;
}template <class V, class K, class HF, class Ex, class Eq, class A>
pair<typename hashtable<V, K, HF, Ex, Eq, A>::iterator,typename hashtable<V, K, HF, Ex, Eq, A>::iterator>
hashtable<V, K, HF, Ex, Eq, A>::equal_range(const key_type& key)
{typedef pair<iterator, iterator> pii;const size_type n = bkt_num_key(key);for (node* first = buckets[n]; first; first = first->next) {if (equals(get_key(first->val), key)) {for (node* cur = first->next; cur; cur = cur->next)if (!equals(get_key(cur->val), key))return pii(iterator(first, this), iterator(cur, this));for (size_type m = n + 1; m < buckets.size(); ++m)if (buckets[m])return pii(iterator(first, this),iterator(buckets[m], this));return pii(iterator(first, this), end());}}return pii(end(), end());
}template <class V, class K, class HF, class Ex, class Eq, class A>
pair<typename hashtable<V, K, HF, Ex, Eq, A>::const_iterator, typename hashtable<V, K, HF, Ex, Eq, A>::const_iterator>
hashtable<V, K, HF, Ex, Eq, A>::equal_range(const key_type& key) const
{typedef pair<const_iterator, const_iterator> pii;const size_type n = bkt_num_key(key);for (const node* first = buckets[n] ; first; first = first->next) {if (equals(get_key(first->val), key)) {for (const node* cur = first->next; cur; cur = cur->next)if (!equals(get_key(cur->val), key))return pii(const_iterator(first, this),const_iterator(cur, this));for (size_type m = n + 1; m < buckets.size(); ++m)if (buckets[m])return pii(const_iterator(first, this),const_iterator(buckets[m], this));return pii(const_iterator(first, this), end());}}return pii(end(), end());
}template <class V, class K, class HF, class Ex, class Eq, class A>
typename hashtable<V, K, HF, Ex, Eq, A>::size_type
hashtable<V, K, HF, Ex, Eq, A>::erase(const key_type& key)
{const size_type n = bkt_num_key(key);node* first = buckets[n];size_type erased = 0;if (first) {node* cur = first;node* next = cur->next;while (next) {if (equals(get_key(next->val), key)) {cur->next = next->next;delete_node(next);next = cur->next;++erased;--num_elements;}else {cur = next;next = cur->next;}}if (equals(get_key(first->val), key)) {buckets[n] = first->next;delete_node(first);++erased;--num_elements;}}return erased;
}template <class V, class K, class HF, class Ex, class Eq, class A>
void hashtable<V, K, HF, Ex, Eq, A>::erase(const iterator& it)
{if (node* const p = it.cur) {const size_type n = bkt_num(p->val);node* cur = buckets[n];if (cur == p) {buckets[n] = cur->next;delete_node(cur);--num_elements;}else {node* next = cur->next;while (next) {if (next == p) {cur->next = next->next;delete_node(next);--num_elements;break;}else {cur = next;next = cur->next;}}}}
}template <class V, class K, class HF, class Ex, class Eq, class A>
void hashtable<V, K, HF, Ex, Eq, A>::erase(iterator first, iterator last)
{size_type f_bucket = first.cur ? bkt_num(first.cur->val) : buckets.size();size_type l_bucket = last.cur ? bkt_num(last.cur->val) : buckets.size();if (first.cur == last.cur)return;else if (f_bucket == l_bucket)erase_bucket(f_bucket, first.cur, last.cur);else {erase_bucket(f_bucket, first.cur, 0);for (size_type n = f_bucket + 1; n < l_bucket; ++n)erase_bucket(n, 0);if (l_bucket != buckets.size())erase_bucket(l_bucket, last.cur);}
}template <class V, class K, class HF, class Ex, class Eq, class A>
inline void
hashtable<V, K, HF, Ex, Eq, A>::erase(const_iterator first,const_iterator last)
{erase(iterator(const_cast<node*>(first.cur),const_cast<hashtable*>(first.ht)),iterator(const_cast<node*>(last.cur),const_cast<hashtable*>(last.ht)));
}template <class V, class K, class HF, class Ex, class Eq, class A>
inline void
hashtable<V, K, HF, Ex, Eq, A>::erase(const const_iterator& it)
{erase(iterator(const_cast<node*>(it.cur),const_cast<hashtable*>(it.ht)));
}//判断是否需要重建,是拿元素个数(计入新增元素个数后)和bucket size进行比较
//故每个bucket(list)最大容量和buckets vectors 大小相同
template <class V, class K, class HF, class Ex, class Eq, class A>
void hashtable<V, K, HF, Ex, Eq, A>::resize(size_type num_elements_hint)
{const size_type old_n = buckets.size();if (num_elements_hint > old_n) {const size_type n = next_size(num_elements_hint);if (n > old_n) {//重分配vector<node*, A> tmp(n, (node*) 0);//新的buckets__STL_TRY {//拷贝for (size_type bucket = 0; bucket < old_n; ++bucket) {node* first = buckets[bucket];//list起始节点while (first) {//拷贝一个bucket里的list//找出结点落在哪个新的bucket中,需要重新计算,n是新桶长度//原本在同一个桶的元素肯能要分到另一个size_type new_bucket = bkt_num(first->val, n);//以下四步建议结合画的图进行处理//从头开始将原结点去除,插入新list是用头插入buckets[bucket] = first->next;//相当于取出当前头结点first->next = tmp[new_bucket];//执行头插入tmp[new_bucket] = first;first = buckets[bucket]; //循环迭代处理         }}buckets.swap(tmp);//对调}
#         ifdef __STL_USE_EXCEPTIONScatch(...) {for (size_type bucket = 0; bucket < tmp.size(); ++bucket) {while (tmp[bucket]) {node* next = tmp[bucket]->next;delete_node(tmp[bucket]);tmp[bucket] = next;}}throw;}
#         endif /* __STL_USE_EXCEPTIONS */}}
}template <class V, class K, class HF, class Ex, class Eq, class A>
void hashtable<V, K, HF, Ex, Eq, A>::erase_bucket(const size_type n, node* first, node* last)
{node* cur = buckets[n];if (cur == first)erase_bucket(n, last);else {node* next;for (next = cur->next; next != first; cur = next, next = cur->next);while (next) {cur->next = next->next;delete_node(next);next = cur->next;--num_elements;}}
}template <class V, class K, class HF, class Ex, class Eq, class A>
void
hashtable<V, K, HF, Ex, Eq, A>::erase_bucket(const size_type n, node* last)
{node* cur = buckets[n];while (cur != last) {node* next = cur->next;delete_node(cur);cur = next;buckets[n] = cur;--num_elements;}
}//注意内存释放问题
template <class V, class K, class HF, class Ex, class Eq, class A>
void hashtable<V, K, HF, Ex, Eq, A>::clear()
{//每个bucketfor (size_type i = 0; i < buckets.size(); ++i) {node* cur = buckets[i];while (cur != 0) {//删节点node* next = cur->next;delete_node(cur);cur = next;}buckets[i] = 0;//内容置为null}num_elements = 0;
}template <class V, class K, class HF, class Ex, class Eq, class A>
void hashtable<V, K, HF, Ex, Eq, A>::copy_from(const hashtable& ht)
{buckets.clear();buckets.reserve(ht.buckets.size());//自己大不动,对方大扩大buckets.insert(buckets.end(), ht.buckets.size(), (node*) 0);__STL_TRY {for (size_type i = 0; i < ht.buckets.size(); ++i) {//复制vector每个元素(头元素)if (const node* cur = ht.buckets[i]) {node* copy = new_node(cur->val);buckets[i] = copy;//拷贝listfor (node* next = cur->next; next; cur = next, next = cur->next) {copy->next = new_node(next->val);copy = copy->next;}}}num_elements = ht.num_elements;//重置结点数}__STL_UNWIND(clear());
}__STL_END_NAMESPACE#endif /* __SGI_STL_INTERNAL_HASHTABLE_H */

hash_set

  • 以hashtable为底层的set,看源码即可。和hash一样,对于float等,除非用户自定义hash_function,否则也无法处理。注意:默认hashtable大小100(193),而不是53,故小数值测试时可能会出现排序的假象。

hash_map

  • 和map的区别在于没有自动排序功能,其余和上面的几乎一致

hash_multiset

  • 采用insert_equal

hash_multimap

  • 采用insert_equal

阅读【hashtable】源码相关推荐

  1. Java8 Hashtable 源码阅读

    一.Hashtable 概述 Hashtable 底层基于数组与链表实现,通过 synchronized 关键字保证在多线程的环境下仍然可以正常使用.虽然在多线程环境下有了更好的替代者 Concurr ...

  2. Java源码详解三:Hashtable源码分析--openjdk java 11源码

    文章目录 注释 哈希算法与映射 线程安全的实现方法 put 操作 get操作 本系列是Java详解,专栏地址:Java源码分析 Hashtable官方文档:Hashtable (Java Platfo ...

  3. hashtable源码解析

    Hashtable 也就是哈希表,是个非常重要的概率,在剖析hashtable源码前,我先简单介绍一下hashtable的原理 哈希表概念 什么是哈希(hash又称散列)? 将任意长度的消息压缩到某一 ...

  4. 逐行阅读redux源码(二)combineReducers

    前情提要 逐行阅读redux源码(一)createStore 认识reducers 在我们开始学习源码之前,我们不妨先来看看何谓reducers: 如图所见,我们可以明白, reducer 是用来对初 ...

  5. C++Primer Plus (第六版)阅读笔记 + 源码分析【目录汇总】

    C++Primer Plus (第六版)阅读笔记 + 源码分析[第一章:预备知识] C++Primer Plus (第六版)阅读笔记 + 源码分析[第二章:开始学习C++] C++Primer Plu ...

  6. webuploader 怎么在react中_另辟蹊径搭建阅读React源码调试环境支持所有React版本细分文件断点调试...

    引言(为什么写这篇文章) 若要高效阅读和理解React源码,搭建调试环境是必不可少的一步.而常规方法:使用react.development.js和react-dom.development.js调试 ...

  7. 【Java集合源码剖析】Hashtable源码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/36191279 Hashtable简介 Hashtable同样是基于哈希表实现的,同样每个元 ...

  8. 阅读react-redux源码(七) - 实现一个react-redux

    阅读react-redux源码 - 零 阅读react-redux源码 - 一 阅读react-redux源码(二) - createConnect.match函数的实现 阅读react-redux源 ...

  9. 阅读react-redux源码(六) - selectorFactory处理store更新

    阅读react-redux源码 - 零 阅读react-redux源码 - 一 阅读react-redux源码(二) - createConnect.match函数的实现 阅读react-redux源 ...

  10. 阅读react-redux源码(五) - connectAdvanced中store改变的事件转发、ref的处理和pure模式的处理

    阅读react-redux源码 - 零 阅读react-redux源码 - 一 阅读react-redux源码(二) - createConnect.match函数的实现 阅读react-redux源 ...

最新文章

  1. 量子力学在计算机上的应用,量子力学在医学科学中的应用
  2. python使用笔记:sys.argv[]的使用
  3. YYDS!怪不得很多朋友去杭州,原来有10W+的福利!
  4. 阿里1582.73亿营收背后的持续交付如何玩?
  5. 怎样远程连接服务器后上传文件,远程登录服务器后怎样上传文件
  6. 利用Eclipse连接JDBC-(SQL Server2008)
  7. CSS伪元素 after 实现鼠标悬浮信息及动画效果
  8. 栈的应用--中序表达式转后序表达式
  9. 如何听节拍器_如何用节拍器卡节拍?节拍器的使用方法!
  10. 手把手教你实现机器学习SVM算法
  11. 2020杭电多校6 1006A Very Easy Graph Problem血泪史
  12. zzulioj1039答案C语言,ZZULIOJ 1037~1045(C语言)
  13. The StL Format(StL 格式)
  14. 2021年度训练联盟热身训练赛第二场 ABCDGJ
  15. linux mysql统计次数_按条件计数 - MySQL统计函数记录_数据库技术_Linux公社-Linux系统门户网站...
  16. Edge、Chrome 1月12日之后继续使用Flash的方法(超级专业,高能预警)
  17. win10设置默认中英文符号
  18. windows下内存检测工具
  19. Proteus8.9 VSM Studio GCC编译器仿真STM32F407ZGT6系列011_lcd1602_并口
  20. 程序员升职加薪靠的是优势,教你发现优势运用优势

热门文章

  1. android版本怎么升级10,Android 10.0(Q OS)系统升级计划Androi
  2. NQI知识|关于知识产权的法律知识
  3. hbase维护操作命令
  4. Mac上好用的滤镜软件
  5. 有哪些非常精致的人生感悟句子?
  6. C语言中的占位符有哪些
  7. Vue3之Suspense
  8. 智能家居主流的五种连接方式
  9. 内联函数和宏定义函数的区别
  10. 计算机应用技术教程答案2017,计算机应用技术教程各章书后练习答案.docx