目录
前言
unordered_set的封装
代码解读
类模板参数
私有嵌套结构 SetKeyOfT
类型别名
公共成员函数
私有成员
insert 函数的详细解读
unordered_map的封装
代码解读
类模板参数
私有嵌套结构 MapKeyOfT
类型别名
公共成员函数
私有成员
operator[] 函数的详细解读
const 版本的 operator[]
前言
unordered_map
和 unordered_set
在 C++ 标准库中是对哈希表的封装。它们是基于哈希桶(开散列)实现的容器,提供了平均常数时间复杂度的插入、查找和删除操作。
-
unordered_map
是一种关联容器,它存储键值对,其中键是唯一的。它使用哈希表来实现,允许快速检索键对应的值。 -
unordered_set
是一种集合容器,它存储唯一的元素。同样基于哈希表实现,用于快速检查元素是否存在于集合中。
以下是 unordered_map
和 unordered_set
的一些关键特性:
-
哈希表实现:内部使用哈希表来存储元素,这意味着元素是无序的,且通常不保证元素的顺序。
-
哈希函数:它们使用哈希函数来确定元素在哈希表中的位置。C++ 标准库为常见数据类型提供了默认的哈希函数,也可以为自定义类型提供专门的哈希函数。
-
处理冲突:当多个元素散列到同一个位置时,
unordered_map
和unordered_set
使用开散列的方法(如分离链接法)来处理冲突。每个哈希桶位置存储一个链表或另一个数据结构,所有散列到该位置的元素都存储在这个结构中。 -
性能:理想情况下,
unordered_map
和unordered_set
提供了平均常数时间复杂度的操作(O(1)),但最坏情况下可能会退化到线性时间复杂度(O(n)),这通常发生在哈希表的负载因子过高,需要进行重新哈希时。
因此,可以说 unordered_map
和 unordered_set
是对哈希桶的高层抽象,提供了方便的接口来管理基于哈希的元素集合。
unordered_set的封装
namespace My_unordered_set {template <class K, class HashFunc = HashFunc<K>>class unordered_set{private:struct SetKeyOfT{const K& operator()(const K& key){return t;}};public:typedef typename HashTable<K, K, SetKeyOfT, HashFunc>::iterator iterator; //iterator是一个类型,不是实例化的对象typedef typename HashTable<K, K, SetKeyOfT, HashFunc>::const_iterator const_iterator;iterator begin(){return _table.begin();}const_iterator begin() const{return _table.begin();}iterator end(){return _table.end();}const_iterator end() const{return _table.end();}bool erase(const K& key){return _table.Erase(key);}iterator find(const K& key){return _table.Find(key);}pair<const_iterator, bool> insert(const K& key){//return _table.Insert(key); //这里返回这个函数,因为它返回pair<iterator, bool>,而我们需要返回pair<const_iterator, bool>auto ret = _table.Insert(key);//用返回的迭代器的成员构造一个const迭代器 //ret.second控制返回是否成功return make_pair(const_iterator(ret.first._node, ret.first._pht, ret.first._hashi), ret.second); //构造的这个const_iterator构造完成之后,只能调用const函数(通过Ref与Ptr进行控制)}private:HashTable<K, K, SetKeyOfT, HashFunc> _table;};
}
代码解读
这段代码定义了一个名为 My_unordered_set
的命名空间,其中包含一个模板类 unordered_set
。这个类模仿了 C++ 标准库中的 unordered_set
,用于存储唯一元素,基于哈希表实现。下面是对这个类的详细解读:
类模板参数
K
:表示集合中存储的元素类型。HashFunc
:表示用于计算哈希值的哈希函数类型,默认为HashFunc<K>
。
私有嵌套结构 SetKeyOfT
这个结构体定义了一个函数对象,它返回其参数的引用。在这个上下文中,它似乎没有被使用,因为它总是返回传入的 key
。这可能是一个设计上的失误,因为通常在哈希表中,我们需要一个函数来提取键值。
struct SetKeyOfT
{const K& operator()(const K& key){return key;}
};
类型别名
iterator
和const_iterator
:这两个类型别名分别用于定义普通迭代器和常量迭代器。它们是基于HashTable
类的迭代器类型。
typedef typename HashTable<K, K, SetKeyOfT, HashFunc>::iterator iterator;
typedef typename HashTable<K, K, SetKeyOfT, HashFunc>::const_iterator const_iterator;
公共成员函数
begin()
和begin() const
:返回一个指向集合中第一个元素的迭代器。end()
和end() const
:返回一个指向集合中最后一个元素之后位置的迭代器。erase(const K& key)
:从集合中删除指定的元素,如果元素存在则返回true
,否则返回false
。find(const K& key)
:在集合中查找指定的元素,并返回一个迭代器指向该元素,如果未找到则返回end()
。insert(const K& key)
:将元素插入集合中,如果元素已存在则不插入,并返回一个pair
,包含一个迭代器指向已存在的或新插入的元素,以及一个布尔值表示插入是否成功。
私有成员
_table
:这是一个HashTable
类的实例,用于实际存储集合中的元素。
insert
函数的详细解读
在 insert
函数中,我们尝试将一个元素插入到哈希表中。这里有一个需要注意的地方:
auto ret = _table.Insert(key);
return make_pair(const_iterator(ret.first._node, ret.first._pht, ret.first._hashi), ret.second);
这里,_table.Insert(key)
返回一个 pair<iterator, bool>
,其中 iterator
是 HashTable
的迭代器。为了返回 pair<const_iterator, bool>
,我们需要将普通的迭代器转换为常量迭代器。这是通过构造一个 const_iterator
来完成的,它接收与普通迭代器相同的参数:节点指针 _node
,指向哈希表的指针 _pht
,以及哈希值 _hashi
。
总的来说,这个 unordered_set
类是一个简化版的哈希集合实现,它基于一个未在此代码段中定义的 HashTable
类。这个类提供了基本的集合操作,如插入、查找和删除元素。
unordered_map的封装
namespace My_unordered_map
{template<typename K, typename V, class HashFunc = HashFunc<K>> //map是K/V结构class unordered_map{private:struct MapKeyOfT{const K& operator()(const pair<K, V>& kv) {return kv.first;}}public:typedef typename HashTable<K, pair<const K, V>, MapKeyOfT, HashFunc>::iterator iterator;typedef typename HashTable<K, pair<const K, V>, MapKeyOfT, HashFunc>::const_iterator const_iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}const_iterator begin() const{return _ht.begin();}const_iterator end() const{return _ht.end();}bool erase(const K& key){return _ht.Erase(key);}iterator find(const K& key){return _ht.Find(key);}pair<iterator, bool> insert(const pair<K, V>& kv){return _ht.Insert(kv);}V& operator[](const K& key){pair<iterator, bool> ret = _table.Insert(pair<K, V>(key, V())); //总是先执行一次插入return ret.first->second; //使用迭代器重载的操作符(迭代器行为类似节点指针)}const V& operator[](const K& key) const{pair<iterator, bool> ret = _table.Insert(pair<K, V>(key, V())); //总是先执行一次插入return ret.first->second; //使用迭代器重载的操作符(迭代器行为类似节点指针)}private:HashTable<K, pair<const K, V>, MapKeyOfT, HashFunc> _table; //借助MapKeyOfT类,获取到的键值K是const修饰过的};}
代码解读
这段代码定义了一个名为 My_unordered_map
的命名空间,其中包含一个模板类 unordered_map
。这个类模仿了 C++ 标准库中的 unordered_map
,用于存储键值对,其中键是唯一的,基于哈希表实现。下面是对这个类的详细解读:
类模板参数
K
:表示键的类型。V
:表示值的类型。HashFunc
:表示用于计算键的哈希值的哈希函数类型,默认为HashFunc<K>
。
私有嵌套结构 MapKeyOfT
这个结构体定义了一个函数对象,它用于从一个键值对 pair<K, V>
中提取键 K
。
struct MapKeyOfT
{const K& operator()(const pair<K, V>& kv){return kv.first;}
}
类型别名
iterator
和const_iterator
:这两个类型别名分别用于定义普通迭代器和常量迭代器。它们是基于HashTable
类的迭代器类型。
typedef typename HashTable<K, pair<const K, V>, MapKeyOfT, HashFunc>::iterator iterator;
typedef typename HashTable<K, pair<const K, V>, MapKeyOfT, HashFunc>::const_iterator const_iterator;
公共成员函数
begin()
和end()
:返回一个指向映射中第一个键值对的迭代器。begin() const
和end() const
:返回一个指向映射中第一个键值对的常量迭代器。erase(const K& key)
:从映射中删除指定键的键值对,如果键存在则返回true
,否则返回false
。find(const K& key)
:在映射中查找指定键的键值对,并返回一个迭代器指向该键值对,如果未找到则返回end()
。insert(const pair<K, V>& kv)
:将键值对插入映射中,如果键已存在则不插入,并返回一个pair
,包含一个迭代器指向已存在的或新插入的键值对,以及一个布尔值表示插入是否成功。operator[](const K& key)
:允许通过键直接访问或插入值。如果键不存在,则插入一个默认构造的值。
私有成员
_table
:这是一个HashTable
类的实例,用于实际存储映射中的键值对。
operator[]
函数的详细解读
operator[]
函数允许通过键直接访问或修改映射中的值。如果键不存在,它会插入一个默认构造的值。
V& operator[](const K& key)
{pair<iterator, bool> ret = _table.Insert(pair<K, V>(key, V())); // 总是先执行一次插入return ret.first->second; // 使用迭代器重载的操作符(迭代器行为类似节点指针)
}
在这个函数中,如果键 key
不存在于映射中,它会创建一个默认构造的值 V()
并与键一起插入到哈希表中。Insert
函数返回一个 pair<iterator, bool>
,其中 iterator
指向新插入的键值对或已存在的键值对,bool
表示是否成功插入了新的键值对。然后,我们通过 ret.first->second
返回值的引用。
注意,这里有一个潜在的问题:如果 V
类型没有默认构造函数,或者默认构造函数的行为不是期望的,那么这段代码将无法正常工作。
const
版本的 operator[]
const V& operator[](const K& key) const
这个函数与非常量版本相同,但是它返回一个常量引用,这意味着不能通过这个函数修改值。然而,这段代码似乎有一个错误,因为在一个常量成员函数中调用 Insert
是不允许的,因为 Insert
可能会修改映射。正确的做法是在非常量版本中插入元素,然后在常量版本中仅返回已存在元素的引用。
总结来说,这个 unordered_map
类是一个简化版的哈希映射实现,它基于一个未在此代码段中定义的 HashTable
类。这个类提供了基本的映射操作,如插入、查找、删除键值对,以及通过键直接访问值。