(十一)hashtable

hashtable

  • 有N个元素,这些元素要放到容器中,且每个元素都可以转化为一个数值。这些元素的个数变化范围是0~2的32次方-1,需要至少2的32次方个元素的大小
  • 由于不可能准备这么大的空间,且元素的个数也不一定到2的32次方。对每个元素编号,采用取余法确定元素要放置的地点,如果容器长度为H,元素的编号为M,则将它放置到M%H处
  • 如果当前位置已经有元素了,则发生了冲突,将它跟在当前元素的后面(采用链表)
  • 如果一个节点的链表太长,就要将该链表打散重排。经验法则是,当元素个数大于篮子的个数,就要将链表打散。即将原来的篮子数扩容为原来的2倍附近的质数,再重新计算每个元素该放置的位置。
  • 篮子的起始数量一般为质数。
//六个模板参数
//HashFcn负则求对象的编号hashcode,ExtractKey负则从一堆东西Value中提取出Key
//EqualKey负则比较key是否相等
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
//哈希表中节点的定义,vector是存放指向节点的指针的容器
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;
};
  • 直接使用hashtable
struct eqstr{
	bool operator() (const char* s1, const char* s2) const
	{ return strcmp(s1, s2)==0; }
};
//为什么不直接传strcmp,而要在外层再封装一层
//strcmp比较两个c风格的字符串是否相等,返回值有-1,0,1,不是bool,所有必需加一层外套

//第三个参数hash<const char*>表示哈希方程,将对象转换位hashcode
//第四个参数必需返回bool值
//模板参数的值如上例
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; }
};

...
//标准库没有提供现成的hash<std::string>
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;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值