STL里的HashTable的分析

J2eeLearner 2003-01-06 04:07:25
//stl_hash_fun.h
template <class _Key> struct hash { };
//这里是hash

//后面的都算是对hash的偏特化,这里需要注意 模板定义的先后顺序
//偏特化必须在后面 。

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); }
};

__STL_TEMPLATE_NULL struct hash<char> {
size_t operator()(char __x) const { return __x; }
};
__STL_TEMPLATE_NULL struct hash<unsigned char> {
size_t operator()(unsigned char __x) const { return __x; }
};
__STL_TEMPLATE_NULL struct hash<signed char> {
size_t operator()(unsigned char __x) const { return __x; }
};
__STL_TEMPLATE_NULL struct hash<short> {
size_t operator()(short __x) const { return __x; }
};
__STL_TEMPLATE_NULL struct hash<unsigned short> {
size_t operator()(unsigned short __x) const { return __x; }
};
__STL_TEMPLATE_NULL struct hash<int> {
size_t operator()(int __x) const { return __x; }
};
__STL_TEMPLATE_NULL struct hash<unsigned int> {
size_t operator()(unsigned int __x) const { return __x; }
};
__STL_TEMPLATE_NULL struct hash<long> {
size_t operator()(long __x) const { return __x; }
};
__STL_TEMPLATE_NULL struct hash<unsigned long> {
size_t operator()(unsigned long __x) const { return __x; }
};

// stl_hash_fun.h里面定义了 hash 函数,针对各种数据类型,重载了hash函数,用于散列
// 除了代入的参数是字符串,其余的都直接返回自己 :( 如果允许用户自己定义hash函数 就好了~ 后面看
// 这里对字符串的散列算法 也比较简单 :) 甚至ugly
// 值得一提的是,这里的Hash 都是使用的 Functor,比Function容易优化,所以效率比较高 :)
...全文
413 点赞 收藏 8
写回复
8 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
J2eeLearner 2003-01-06


template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::clear()
// 为何不用_M_erase_bucket(const size_type __n, _Node* __last) 呢?
{
for (size_type __i = 0; __i < _M_buckets.size(); ++__i) {
_Node* __cur = _M_buckets[__i];
while (__cur != 0) {
_Node* __next = __cur->_M_next;
_M_delete_node(__cur);
__cur = __next;
}
_M_buckets[__i] = 0;
}
_M_num_elements = 0;
}

template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
::resize(size_type __num_elements_hint)
{
const size_type __old_n = _M_buckets.size();
if (__num_elements_hint > __old_n) {
const size_type __n = _M_next_size(__num_elements_hint);
// 得到下一个Vector可能的长度
if (__n > __old_n) {
vector<_Node*, _All> __tmp(__n, (_Node*)(0),
_M_buckets.get_allocator());
__STL_TRY {
for (size_type __bucket = 0; __bucket < __old_n; ++__bucket) {
_Node* __first = _M_buckets[__bucket];
while (__first) {
size_type __new_bucket = _M_bkt_num(__first->_M_val, __n);
_M_buckets[__bucket] = __first->_M_next;
__first->_M_next = __tmp[__new_bucket];
__tmp[__new_bucket] = __first;
__first = _M_buckets[__bucket];
}//把所有的链表接送过来 :)
}
_M_buckets.swap(__tmp); //修改一些参数
}
catch(...) {
for (size_type __bucket = 0; __bucket < __tmp.size(); ++__bucket) {
while (__tmp[__bucket]) {
_Node* __next = __tmp[__bucket]->_M_next;
_M_delete_node(__tmp[__bucket]);
__tmp[__bucket] = __next;
}
}
throw;
}
}
}
}

template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
::_M_copy_from(const hashtable& __ht)
{
_M_buckets.clear(); //先清空自己
_M_buckets.reserve(__ht._M_buckets.size());// 分配内存
_M_buckets.insert(_M_buckets.end(), __ht._M_buckets.size(), (_Node*) 0);
__STL_TRY {
for (size_type __i = 0; __i < __ht._M_buckets.size(); ++__i) {
if (const _Node* __cur = __ht._M_buckets[__i]) {
_Node* __copy = _M_new_node(__cur->_M_val);
_M_buckets[__i] = __copy;

for (_Node* __next = __cur->_M_next;
__next;
__cur = __next, __next = __cur->_M_next) {
__copy->_M_next = _M_new_node(__next->_M_val);
__copy = __copy->_M_next;
} //Vector元素不为空,就要把后面的整个链表拷贝一次!
}
}
_M_num_elements = __ht._M_num_elements;
}
__STL_UNWIND(clear());
}
回复
J2eeLearner 2003-01-06
template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
pair<typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::iterator,
typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::iterator>
hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::equal_range(const key_type& __key)
{
typedef pair<iterator, iterator> _Pii;
const size_type __n = _M_bkt_num_key(__key);

for (_Node* __first = _M_buckets[__n]; __first; __first = __first->_M_next)
if (_M_equals(_M_get_key(__first->_M_val), __key))
// 找到了一个 ,记下位置 在__first里面
{
for (_Node* __cur = __first->_M_next; __cur; __cur = __cur->_M_next)
// (不同的key可能在同一个链表中,相同的key肯定相邻,)
// 在此链表中继续往后找,在此过程中发现没有了,最理想的情况了
if (!_M_equals(_M_get_key(__cur->_M_val), __key))
return _Pii(iterator(__first, this), iterator(__cur, this));
//返回, 这里的_cur也在链表中,只是_cur的key不是查找的key罢了!

// 这里是上面没有返回的情况,也就是_first就在链表的最后了,
//因为stl里面的range的表示的特殊性,我们还需要找到下一个元素,这样才能构成圆满的range
//这里的找,就不是在刚才的链表中找了,而是在hashtable::Vector里面找,只要有下一个元素就行
for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m)
if (_M_buckets[__m])
// 还好,hashtable中在后面还有其它元素, 谢天谢地! 就这样吧!
return _Pii(iterator(__first, this),
iterator(_M_buckets[__m], this));

return _Pii(iterator(__first, this), end());
// 5555555555 要找的元素竟然是hashtable的最后一个元素,那么只能用end()了!
}

return _Pii(end(), end()); // 这个就是啥都没有拉,__key在hashtable里面根本就没有 :(

// 这里的_Pii 就是 pair<iterator, iterator> :)
// 看到这里的pair的构造方法,我就想问make_pair还有啥用?

} // 这里需要注意的是STL里面的range的表示 [first,second) ,second是后一个元素。
// 如果没有后一个元素,则second就是end().

template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::size_type
hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::erase(const key_type& __key)
// 删除某个key的所有元素
{
const size_type __n = _M_bkt_num_key(__key); //得到散列值
_Node* __first = _M_buckets[__n];//_first就是链表表头了
size_type __erased = 0;

if (__first) //可能存在key这样的元素,那么就在链表中删除吧!
{
_Node* __cur = __first;
_Node* __next = __cur->_M_next;

while (__next) {
//在链表中还可能有其它的key哦,别鲁莽,对比一下
if (_M_equals(_M_get_key(__next->_M_val), __key)) {
// 是要找的东西了,删掉吧! 修改一些参数
__cur->_M_next = __next->_M_next;
_M_delete_node(__next);
__next = __cur->_M_next;
++__erased;
--_M_num_elements;
}
else {
__cur = __next;
__next = __cur->_M_next;
}
}

// 这就是不带头节点的链表的缺点了! 竟然还要这么麻烦!
if (_M_equals(_M_get_key(__first->_M_val), __key)) {
_M_buckets[__n] = __first->_M_next;
_M_delete_node(__first);
++__erased;
--_M_num_elements;
}
}
return __erased; //删除的元素个数
}

template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::erase(const iterator& __it)
{
if (_Node* const __p = __it._M_cur) {
// :) 别带入的参数_it是end() :)
const size_type __n = _M_bkt_num(__p->_M_val);
_Node* __cur = _M_buckets[__n];
// 赶紧找到__it所在的链表

//下面就是一个不表头的链表里面删除节点的操作了
if (__cur == __p) {
_M_buckets[__n] = __cur->_M_next;
_M_delete_node(__cur);
--_M_num_elements;
}
else {
_Node* __next = __cur->_M_next;
while (__next) {
if (__next == __p) {
__cur->_M_next = __next->_M_next;
_M_delete_node(__next);
--_M_num_elements;
break;
}
else {
__cur = __next;
__next = __cur->_M_next;
}
}
}
}
}

template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
::erase(iterator __first, iterator __last)
//删除range
{
size_type __f_bucket = __first._M_cur ?
_M_bkt_num(__first._M_cur->_M_val) : _M_buckets.size();
size_type __l_bucket = __last._M_cur ?
_M_bkt_num(__last._M_cur->_M_val) : _M_buckets.size();

//先得到两者所在的Vector的下标

if (__first._M_cur == __last._M_cur)
return;
else if (__f_bucket == __l_bucket) //在同一个链表里面
_M_erase_bucket(__f_bucket, __first._M_cur, __last._M_cur);
else { // 不在同一个链表里面,那么就按秩序所有的都删除吧!
_M_erase_bucket(__f_bucket, __first._M_cur, 0);
for (size_type __n = __f_bucket + 1; __n < __l_bucket; ++__n)
_M_erase_bucket(__n, 0);
if (__l_bucket != _M_buckets.size())
_M_erase_bucket(__l_bucket, __last._M_cur);
}
}

template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
::_M_erase_bucket(const size_type __n, _Node* __first, _Node* __last)
//在一个链表里面删range,
{
_Node* __cur = _M_buckets[__n];
if (__cur == __first)
_M_erase_bucket(__n, __last);
else {
_Node* __next;
for (__next = __cur->_M_next;
__next != __first;
__cur = __next, __next = __cur->_M_next)
; //找到_first在链表里的位置
while (__next) {
__cur->_M_next = __next->_M_next;
_M_delete_node(__next);
__next = __cur->_M_next;
--_M_num_elements;
}
}
}

template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
::_M_erase_bucket(const size_type __n, _Node* __last)
//把链表里面到__last的所有东西都删了!
{
_Node* __cur = _M_buckets[__n];
while (__cur != __last) {
_Node* __next = __cur->_M_next;
_M_delete_node(__cur);
__cur = __next;
_M_buckets[__n] = __cur;
--_M_num_elements;
}
}
回复
J2eeLearner 2003-01-06
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 _M_next_size(size_type __n) const
{ return __stl_next_prime(__n); }
//Vector将要的长度?

void _M_initialize_buckets(size_type __n)
{
const size_type __n_buckets = _M_next_size(__n);
// :) 得到vector的长度
_M_buckets.reserve(__n_buckets); // reserve方法 ,强制分配内存
_M_buckets.insert(_M_buckets.end(), __n_buckets, (_Node*) 0); // :)还是回到insert
_M_num_elements = 0;
}

size_type _M_bkt_num_key(const key_type& __key) const
{
return _M_bkt_num_key(__key, _M_buckets.size());
}

size_type _M_bkt_num(const value_type& __obj) const
{
return _M_bkt_num_key(_M_get_key(__obj));
}

size_type _M_bkt_num(const value_type& __obj, size_t __n) const
{
return _M_bkt_num_key(_M_get_key(__obj), __n);
}

size_type _M_bkt_num_key(const key_type& __key, size_t __n) const
{
return _M_hash(__key) % __n;
}
//_M_bkt_num()用于计算得到 当前HashTable应该插入的位置,
//所有的都集中到了这里重载的最后一个函数上面,利用到了_M_hash()函数,,而参数_n就是Hash::_M_buckets的长度
//因为_M_buckets是vector,这里的位置可以用int表示,就是在vector里面的下标


_Node* _M_new_node(const value_type& __obj)
{
_Node* __n = _M_get_node(); // 分配内存
__n->_M_next = 0;
__STL_TRY {
construct(&__n->_M_val, __obj); //构造函数
return __n;
}
__STL_UNWIND(_M_put_node(__n));
}

void _M_delete_node(_Node* __n)
{
destroy(&__n->_M_val); //析构
_M_put_node(__n); // 回收内存
}

void _M_erase_bucket(const size_type __n, _Node* __first, _Node* __last);
void _M_erase_bucket(const size_type __n, _Node* __last);

void _M_copy_from(const hashtable& __ht);

};
//下面的都是没有内联的成员函数 以及一些 和hashtable相关的辅助函数

template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
pair<typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::iterator, bool>
hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
::insert_unique_noresize(const value_type& __obj)
//插入一个节点,注意这里的unique, 如果查找key发现存在了,那么就直接返回了
{
const size_type __n = _M_bkt_num(__obj);
_Node* __first = _M_buckets[__n];

for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj)))
return pair<iterator, bool>(iterator(__cur, this), false);
// 已经存在了,直接返回,注意这里的返回结果是pair<> ,pair::second用于说明插入失败

_Node* __tmp = _M_new_node(__obj);
__tmp->_M_next = __first;
_M_buckets[__n] = __tmp; // 插入 :)
++_M_num_elements; //hashtable 所有的元素+1
return pair<iterator, bool>(iterator(__tmp, this), true); //插入成功
}

template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::iterator
hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
::insert_equal_noresize(const value_type& __obj)
// 注意:这里的插入和上面的不同,上面的是 如果key已经存在,则直接返回
// 而这里是 key已经存在,则仍然插入
{
const size_type __n = _M_bkt_num(__obj);
_Node* __first = _M_buckets[__n];

for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) {
_Node* __tmp = _M_new_node(__obj);
__tmp->_M_next = __cur->_M_next;
__cur->_M_next = __tmp;
++_M_num_elements;
return iterator(__tmp, this);
} //还是插入

_Node* __tmp = _M_new_node(__obj);
__tmp->_M_next = __first;
_M_buckets[__n] = __tmp;
++_M_num_elements;
return iterator(__tmp, this);
} // 注意这里还是会查找一次,对应的key是否存在?
// 这里的方法也就保证了具有相同key的元素会在同一个链表的相邻位置
// 如果没有查找,只是粗鲁的插入,不能保证这点
// 而相同的key的节点在相邻位置,这是很重要的 :)
// 根据一个key,求得他的range,就需要这样的特点. equal_range()就是这么一个例子

template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::reference
hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::find_or_insert(const value_type& __obj)
{
resize(_M_num_elements + 1);

size_type __n = _M_bkt_num(__obj);
_Node* __first = _M_buckets[__n];

for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj)))
return __cur->_M_val; //找到啦,返回

//没有,插入吧!
_Node* __tmp = _M_new_node(__obj);
__tmp->_M_next = __first;
_M_buckets[__n] = __tmp;
++_M_num_elements;
return __tmp->_M_val;
}// 查找某个元素:有了就直接返回,否则插入
回复
superxs 2003-01-06
顶~
回复
春风老少年 2003-01-06
哦~,原来如此啊~
那,UP~
回复
J2eeLearner 2003-01-06
iterator begin()
{
for (size_type __n = 0; __n < _M_buckets.size(); ++__n)
if (_M_buckets[__n])
return iterator(_M_buckets[__n], this);
return end();
}// 这也就涉及到HashTable的数据结构,从_M_buckets的头开始查询每个元素!

iterator end() { return iterator(0, this); }
// :) 又是有关iterator的内容哦,end()不是指向最后一个元素,而是指向最后一个元素的后面的位置,这里用0代入
friend bool
operator== __STL_NULL_TMPL_ARGS (const hashtable&, const hashtable&);

public:

size_type bucket_count() const { return _M_buckets.size(); }
// :) 这个也public?

size_type max_bucket_count() const
{ return __stl_prime_list[__stl_num_primes - 1]; }
//Hash内部定义的Vector可能的最大长度,这个长度和Vector自己本身能够达到的最大长度是不一样的
//也有可能内存不够,Vector根本达不到这么长。 也有可能Vector可以比这个还要长,但是hashtable没有用那么长

size_type elems_in_bucket(size_type __bucket) const
{
size_type __result = 0;
for (_Node* __cur = _M_buckets[__bucket]; __cur; __cur = __cur->_M_next)
__result += 1;
return __result;
}//从_M_buckets[__bucket]这个头节点开始,有多少个有效节点。
//不同key值 经过散列之后,也有可能在同一个链表中

pair<iterator, bool> insert_unique(const value_type& __obj)
{
resize(_M_num_elements + 1);
return insert_unique_noresize(__obj);
}

iterator insert_equal(const value_type& __obj)
{
resize(_M_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);

template <class _InputIterator>
void insert_unique(_InputIterator __f, _InputIterator __l)
{
insert_unique(__f, __l, __ITERATOR_CATEGORY(__f)); //利用这里的tag,选择最适合的insert_unique
}

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) //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) //forward_iterator_Tag
{
size_type __n = 0;
distance(__f, __l, __n);
resize(_M_num_elements + __n); //这里需要调整容器的大小,:)input_iterator不需要
// 原因会在input_iterator介绍
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(_M_num_elements + __n);
for ( ; __n > 0; --__n, ++__f)
insert_equal_noresize(*__f);
}
//所有的insert_unique,和insert_equal都 集中到了insert_equal_noresize()上面来了
//在后面会有描述

reference find_or_insert(const value_type& __obj);

iterator find(const key_type& __key)
{
size_type __n = _M_bkt_num_key(__key); //得到插入的位置,也就是vector的下标
_Node* __first;
for ( __first = _M_buckets[__n]; //这里就是根据下标找到Vector里面的当前元素
__first && !_M_equals(_M_get_key(__first->_M_val), __key);
//这里是如何结束? 指针非空是肯定的,还需要比较两个key是否相等
//也有可能不同的key,经过散列之后,在同样的一个位置哦,所以这里的key的比较不能少的
__first = __first->_M_next) //不停的后移, 也就是Vector里面一个元素作为链表头的链表了
{}
return iterator(__first, this); // :) iterator! ++iterator的操作 和这里很查找很相似了
}

const_iterator find(const key_type& __key) const
{
size_type __n = _M_bkt_num_key(__key);
const _Node* __first;
for ( __first = _M_buckets[__n];
__first && !_M_equals(_M_get_key(__first->_M_val), __key);
__first = __first->_M_next)
{}
return const_iterator(__first, this);
}

size_type count(const key_type& __key) const
{
const size_type __n = _M_bkt_num_key(__key); //得到散列值
size_type __result = 0;

for (const _Node* __cur = _M_buckets[__n]; __cur; __cur = __cur->_M_next)
if (_M_equals(_M_get_key(__cur->_M_val), __key))
++__result; //在一个链表里面,计算和_key相同的key的次数
return __result;
}
回复
J2eeLearner 2003-01-06
template <class _Val>
struct _Hashtable_node
{
_Hashtable_node* _M_next;
_Val _M_val; //存放节点的值
};

//为了方便,这里程序给我搬动过了 :)


// 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] =
{
53ul, 97ul, 193ul, 389ul, 769ul,
1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
1610612741ul, 3221225473ul, 4294967291ul
}; //定义一个数组,存放一些数字 :)
//就是用于定义Hash表内部的Vector的长度了 这个数字有点恐怖

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);
//如果把_N放到上面的_stl_prime_list这个排好序数组中去,应该的位置是??
return pos == __last ? *(__last - 1) : *pos;
// 这就是涉及到STL里面的iterator了,如果lower_bound查询失败,返回_last,而_last已经指向数组之外的位置了
// 所以这里后来自己动手__last-1 。
} //


//Hash表的Alloc内存分配,和其他的容器都不一样,没有定义自己的Alloc !

template <class _Val, class _Key, class _HashFcn,
class _ExtractKey, class _EqualKey, class _Alloc>
class hashtable {
public:
typedef _Key key_type;
typedef _Val value_type;
typedef _HashFcn hasher;
typedef _EqualKey key_equal;
// 先解释一下这里的模板参数的作用。
// Key 散列和查找时的关键字
// Data HashTable里面存放的数据
// HashFcn 这就是Hash Functor了,你可以自己定义,也可以使用系统的了 :)
// EqualKey 这是个二元谓词,具体的作用就是判断两个key是否相等
// Alloc Alloc
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;
private:
typedef _Hashtable_node<_Val> _Node; //节点
private:
hasher _M_hash;
key_equal _M_equals;
_ExtractKey _M_get_key; // 这是一个Functor,用于得到某个元素节点的key!
// 这和Hash函数是不一样的,Hash函数是 知道了key 求得hash值
// 而这里是知道了Vlaue,求得其key值 这两个值是不一样的
vector<_Node*,_Alloc> _M_buckets;
size_type _M_num_elements; //hashtable的元素个数
// 再来看一下Hash表的数据结构 , 这里采用的是_M_buckets,他自己本身是一个Vector
// 里面的元素是指针,用于指向Hash表的真正的元素,而具有相同key的元素,也就构成了一个链表
// 链表的头节点也就是这里的_M_buckets里面的某个元素。

public:

hasher hash_funct() const { return _M_hash; }
key_equal key_eq() const { return _M_equals; }

typedef typename _Alloc_traits<_Val,_Alloc>::allocator_type allocator_type;
allocator_type get_allocator() const { return _M_node_allocator; }
private:
typename _Alloc_traits<_Node, _Alloc>::allocator_type _M_node_allocator;
_Node* _M_get_node() { return _M_node_allocator.allocate(1); }
void _M_put_node(_Node* __p) { _M_node_allocator.deallocate(__p, 1); }
// 因为 HashTable没有像别的container一样定义Alloc_base,
// 所以需要在自己里面定义上面这几个和内存分配相关的方法。这几个方法的作用都已经很熟悉了~

public:
typedef _Hashtable_iterator<_Val,_Key,_HashFcn,_ExtractKey,_EqualKey,_Alloc>
iterator;
typedef _Hashtable_const_iterator<_Val,_Key,_HashFcn,_ExtractKey,_EqualKey,
_Alloc>
const_iterator;

friend struct
_Hashtable_iterator<_Val,_Key,_HashFcn,_ExtractKey,_EqualKey,_Alloc>;
friend struct
_Hashtable_const_iterator<_Val,_Key,_HashFcn,_ExtractKey,_EqualKey,_Alloc>;
//学习哦,友元模板 :)

public:
hashtable(size_type __n,
const _HashFcn& __hf,
const _EqualKey& __eql,
const _ExtractKey& __ext,
const allocator_type& __a = allocator_type())
: __HASH_ALLOC_INIT(__a)
_M_hash(__hf),
_M_equals(__eql),
_M_get_key(__ext),
_M_buckets(__a),
_M_num_elements(0)
{
_M_initialize_buckets(__n);
}

hashtable(size_type __n,
const _HashFcn& __hf,
const _EqualKey& __eql, // 比上面少了_ExtractKey 这个参数,使用默认的
const allocator_type& __a = allocator_type())
: __HASH_ALLOC_INIT(__a)
_M_hash(__hf),
_M_equals(__eql),
_M_get_key(_ExtractKey()),
_M_buckets(__a),
_M_num_elements(0)
{
_M_initialize_buckets(__n);
}

hashtable(const hashtable& __ht)
: __HASH_ALLOC_INIT(__ht.get_allocator())
_M_hash(__ht._M_hash),
_M_equals(__ht._M_equals),
_M_get_key(__ht._M_get_key),
_M_buckets(__ht.get_allocator()),
_M_num_elements(0)
{
_M_copy_from(__ht);
} // 拷贝构造函数,太夸张了!

hashtable& operator= (const hashtable& __ht)
{
if (&__ht != this) {
clear(); // 先将自己的所有元素清除掉,clear会负责如何的清除,以及释放内存
_M_hash = __ht._M_hash;
_M_equals = __ht._M_equals;
_M_get_key = __ht._M_get_key;
_M_copy_from(__ht); //拷贝过来~
}
return *this;
} // operator =, 需要检查自赋值

~hashtable() { clear(); }

size_type size() const { return _M_num_elements; } //
size_type max_size() const { return size_type(-1); }
bool empty() const { return size() == 0; }

void swap(hashtable& __ht)
{
__STD::swap(_M_hash, __ht._M_hash);
__STD::swap(_M_equals, __ht._M_equals);
__STD::swap(_M_get_key, __ht._M_get_key);
_M_buckets.swap(__ht._M_buckets);
__STD::swap(_M_num_elements, __ht._M_num_elements);
} //交换, 把所有的参数都交换,就完成任务了,不需要Temp HashTable 然后赋值两次完成
回复
J2eeLearner 2003-01-06
//iterator 开始
template <class _Val, class _Key, class _HashFcn,
class _ExtractKey, class _EqualKey, class _Alloc>
struct _Hashtable_iterator {
typedef hashtable<_Val,_Key,_HashFcn,_ExtractKey,_EqualKey,_Alloc>
_Hashtable;
typedef _Hashtable_iterator<_Val, _Key, _HashFcn,
_ExtractKey, _EqualKey, _Alloc>
iterator;
typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn,
_ExtractKey, _EqualKey, _Alloc>
const_iterator;
typedef _Hashtable_node<_Val> _Node;

typedef forward_iterator_tag iterator_category;
typedef _Val value_type;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
typedef _Val& reference;
typedef _Val* pointer;

_Node* _M_cur; //指向当前的节点
_Hashtable* _M_ht; // 当前iterator所指向的Hash表

_Hashtable_iterator(_Node* __n, _Hashtable* __tab)
: _M_cur(__n), _M_ht(__tab) {}
_Hashtable_iterator() {}
reference operator*() const { return _M_cur->_M_val; }

pointer operator->() const { return &(operator*()); }

iterator& operator++();
iterator operator++(int); //最关键的就是这两个operator,将会在后面声明。

bool operator==(const iterator& __it) const
{ return _M_cur == __it._M_cur; }
bool operator!=(const iterator& __it) const
{ return _M_cur != __it._M_cur; }
};

template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
class _All>
inline _Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>
_Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>::operator++(int)
{
iterator __tmp = *this;
++*this;
return __tmp;
}

template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
class _All>
_Hashtable_const_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>&
_Hashtable_const_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>::operator++()
{
const _Node* __old = _M_cur;
_M_cur = _M_cur->_M_next;
if (!_M_cur) {
size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val);
while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size())
_M_cur = _M_ht->_M_buckets[__bucket];
}
return *this;
} // 这一步才是最最关键的 :) 不过涉及到Hash的内部的数据结构 。

template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
class _All>
_Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>&
_Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>::operator++()
{
const _Node* __old = _M_cur;
_M_cur = _M_cur->_M_next;
if (!_M_cur) {
size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val);
while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size())
_M_cur = _M_ht->_M_buckets[__bucket];
}
return *this;
}

template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
class _All>
inline forward_iterator_tag
iterator_category(const _Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>&)
{
return forward_iterator_tag();
}

template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
class _All>
inline _Val*
value_type(const _Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>&)
{
return (_Val*) 0;
}

template <class _Val, class _Key, class _HF, class _ExK, class _EqK,
class _All>
inline hashtable<_Val,_Key,_HF,_ExK,_EqK,_All>::difference_type*
distance_type(const _Hashtable_iterator<_Val,_Key,_HF,_ExK,_EqK,_All>&)
{
return (hashtable<_Val,_Key,_HF,_ExK,_EqK,_All>::difference_type*) 0;
}

template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
inline bool operator==(const hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>& __ht1,
const hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>& __ht2)
{
typedef typename hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>::_Node _Node;
if (__ht1._M_buckets.size() != __ht2._M_buckets.size())
return false;
for (int __n = 0; __n < __ht1._M_buckets.size(); ++__n) {
_Node* __cur1 = __ht1._M_buckets[__n];
_Node* __cur2 = __ht2._M_buckets[__n];
for ( ; __cur1 && __cur2 && __cur1->_M_val == __cur2->_M_val;
__cur1 = __cur1->_M_next, __cur2 = __cur2->_M_next)
{}
if (__cur1 || __cur2)
return false;
}
return true;
}

template <class _Val, class _Key, class _HF, class _Extract, class _EqKey,
class _All>
inline void swap(hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht1,
hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht2) {
__ht1.swap(__ht2);
}

// _hash_const_iterator 被忽略了, 和上面的iterator几乎一致
回复
发动态
发帖子
工具平台和程序库
创建于2007-09-28

2.4w+

社区成员

C/C++ 工具平台和程序库
申请成为版主
社区公告
暂无公告