目录
1. unordered_map是存储
2. 在unordered_map中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此
键关联。键和映射值的类型可能不同。
3. 在内部,unordered_map没有对
4. unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭
代方面效率较低。
5. unordered_map实现了直接访问操作符(operator[ ]),它允许使用key作为参数直接访问
value。
6. 它的迭代器是正向迭代器
1. unordered_map的构造
| 函数声明 | 功能介绍 |
| unordered_map | 构造不同格式的unordered_map对象 |
2. unordered_map的容量
| 函数声明 | 功能介绍 |
| bool empty() const | 检测unordered_map是否为空 |
| size_t size() const | 获取unordered_map的有效元素个数 |
3. unordered_map的迭代器
| 函数声明 | 功能介绍 |
| begin | 返回unordered_map第一个元素的迭代器 |
| end | 返回unordered_map最后一个元素下一个位置的迭代器 |
| cbegin | 返回unordered_map第一个元素的const迭代器 |
| cend | 返回unordered_map最后一个元素下一个位置的const迭代器 |
4. unordered_map的元素访问
| 函数声明 | 功能介绍 |
| operator[] | 返回与key对应的value,没有一个默认值 |
5. unordered_map的查询
| 函数声明 | 功能介绍 |
| iterator find(const K& key) | 返回key在哈希桶中的位置 |
| size_t count(const K& key) | 返回哈希桶中关键码为key的键值对的个数 |
注意:unordered_map中key是不能重复的,因此count函数的返回值最大为1
6. unordered_map的修改操作
| 函数声明 | 功能介绍 |
| insert | 向容器中插入键值对 |
| erase | 删除容器中的键值对 |
| void clear() | 清空容器中有效元素个数 |
| void swap(unordered_map&) | 交换两个容器中的元素 |
7. unordered_map的桶操作
| 函数声明 | 功能介绍 |
| size_t bucket_count()const | 返回哈希桶中桶的总个数 |
| size_t bucket_size(size_t n)const | 返回n号桶中有效元素的总个数 |
| size_t bucket(const K& key) | 返回元素key所在的桶号 |
与unordered_map类似,详情见文档unordered_set
unordered系列的关联式容器之所以效率比较高,是因为其底层使用了哈希结构。
顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码的多次比较。顺序查找时间复杂度为O(N),平衡树中为树的高度,即
O(log_2 N),搜索的效率取决于搜索过程中元素的比较次数。
理想的搜索方法:可以不经过任何比较,一次直接从表中得到要搜索的元素。
如果构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。
当向该结构中:
插入元素:
根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放。
搜索元素:
对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置
取元素比较,若关键码相等,则搜索成功
该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称
为哈希表(Hash Table)(或者称散列表)。
例如:数据集合{1,7,6,4,5,9};
哈希函数设置为:hash(key) = key % capacity ; capacity为存储元素底层空间总的大小。
问题:如果继续向上述哈希表中插入44,会出现什么问题?
上述问题中,不同关键字通过相同哈希函数计算出相同的哈希地址,该种现象称为哈希冲突
或哈希碰撞。
把具有不同关键码而具有相同哈希地址的数据元素称为“同义词”。
发生哈希冲突该如何处理呢?
引起哈希冲突的一个原因可能是:哈希函数设计不够合理。
哈希函数设计原则:
哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值
域必须在0到m-1之间
哈希函数计算出来的地址能均匀分布在整个空间中
哈希函数应该比较简单
常见哈希函数:
1. 直接定址法--(常用)
取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B
优点:简单、均匀
缺点:需要事先知道关键字的分布情况
使用场景:适合查找比较小且连续的情况
例题:字符串中的第一个唯一字符
- class Solution {
- public:
- int firstUniqChar(string s) {
- int hash[256] = {0};
- for(int i = 0; i < s.size(); i++){
- hash[s[i]]++;
- }
- for(int i = 0; i < s.size(); i++){
- if(hash[s[i]] == 1){
- return i;
- }
- }
- return -1;
- }
- };
2. 除留余数法--(常用)
设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,
按照哈希函数:Hash(key) = key% p(p<=m),将关键码转换成哈希地址。
注意:哈希函数设计的越精妙,产生哈希冲突的可能性就越低,但是无法避免哈希冲突
解决哈希冲突两种常见的方法是:闭散列和开散列
闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到冲突位置中的“下一个” 空位置中去。
那如何寻找下一个空位置呢?
1. 线性探测
比如2.1中的场景,现在需要插入元素44,先通过哈希函数计算哈希地址,hashAddr为4,
因此44理论上应该插在该位置,但是该位置已经放了值为4的元素,即发生哈希冲突。
线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。
插入:
通过哈希函数获取待插入元素在哈希表中的位置
如果该位置中没有元素则直接插入新元素,如果该位置中有元素发生哈希冲突,使用线性探测找到下一个空位置,插入新元素。

删除:
采用闭散列处理哈希冲突时,不能随便物理删除哈希表中已有的元素,若直接删除元素
会影响其他元素的搜索。比如删除元素4,如果直接删除掉,44查找起来可能会受影响。因此线性探测采用标记的伪删除法来删除一个元素。
- // 哈希表每个空间给个标记
- // EMPTY此位置空, EXIST此位置已经有元素, DELETE元素已经删除
- enum State
- {EMPTY, EXIST, DELETE};
载荷因子:
为了解决 “哈希表什么情况下进行扩容?如何扩容?” 的问题,我们引入载荷因子的概念。
载荷因子 = 表中元素个数 / 散列表容量;
载荷因子越大,表中元素越多,产生冲突可能性越大;
载荷因子越小,表中元素越少,产生冲突可能性越小;
当达到载荷因子我们就扩容,如果载荷因子设置的太小,空间资源浪费就多,载荷因子设置越大,产生冲突的可能性就越大。因此,一般设置载荷因子为 0.7——0.8。
线性探测简要实现哈希表代码如下:
- enum State//标志位
- {
- EMPTY,
- EXIST,
- DELETE
- };
-
- template<class K,class V>
- struct HashData//节点元素包含键值对和标志位
- {
- pair
_kv; - State _state = EMPTY;
- };
-
- template<class K>
- struct HashFunc//用于方便比较的仿函数
- {
- size_t operator()(const K& key)
- {
- return (size_t)key;
- }
- };
-
- //特化
- template<>
- struct HashFunc
- {
- size_t operator()(const string& key)
- {
- size_t val = 0;
- for (auto ch : key)
- {
- //防止出现abc = cba 这种情况,有大佬提出加每个字符前*131
- val *= 131;
- val += ch;
- }
- return val;
- }
- };
-
- //因为如果K为string类型,无法用 % 来实现映射关系,因此我们写个Hash仿函数
- template<class K, class V, class Hash = HashFunc
> - class HashTable
- {
- public:
- bool Insert(const pair
& kv) - {
- if (Find(kv.first))
- return false;
-
- //表为空或载荷因子超70%就扩容
- if (_tables.size() == 0 || 10 * _size / _tables.size() >= 7)
- {
- size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
- HashTable
newHT; - newHT._tables.resize(newSize);
- //旧表数据映射到新表
- for (auto e : _tables)
- {
- if (e._state == EXIST)
- {
- newHT.Insert(e._kv);
- }
- }
- _tables.swap(newHT._tables);
- }
-
- Hash hash;
- size_t hashi = hash(kv.first) % _tables.size();
- //线性探测
- while (_tables[hashi]._state == EXIST)
- {
- hashi++;
- hashi %= _tables.size();
- }
- _tables[hashi]._kv = kv;
- _tables[hashi]._state = EXIST;
- ++_size;
-
- return true;
- }
-
- HashData
* Find(const K& key) - {
- if (_tables.size() == 0)
- {
- return nullptr;
- }
-
- Hash hash;
- size_t hashi = hash(key) % _tables.size();
- while (_tables[hashi]._state != EMPTY)
- {
- if (_tables[hashi]._state != DELETE && _tables[hashi]._kv.first == key)
- {
- return &_tables[hashi];
- }
- hashi++;
- hashi %= _tables.size();
- }
- return nullptr;
- }
-
- bool Erase(const K& key)
- {
- HashData
* ret = Find(key); - if (ret)
- {
- ret->_state = DELETE;
- --_size;
- return true;
- }
- else
- {
- return false;
- }
- }
-
-
- private:
- vector
> _tables; - size_t _size = 0;//存储多少有效数据
- };
总结:
线性探测优点:实现非常简单
线性探测缺点:某个位置冲突很多的情况下,互相占用,冲突一片,如下图:
2. 二次探测
二次探测不是探测二次,是探测2的 i 次方:
二次探测只需要把原来线性探测略微改动一下即可:
- bool Insert(const pair
& kv) - {
- if (Find(kv.first))
- return false;
-
- //表为空或载荷因子超70%就扩容
- if (_tables.size() == 0 || 10 * _size / _tables.size() >= 7)
- {
- size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
- HashTable
newHT; - newHT._tables.resize(newSize);
- //旧表数据映射到新表
- for (auto e : _tables)
- {
- if (e._state == EXIST)
- {
- newHT.Insert(e._kv);
- }
- }
- _tables.swap(newHT._tables);
- }
-
- Hash hash;
- size_t start = hash(kv.first) % _tables.size();
- size_t i = 0;
- size_t hashi = start;
- //二次探测
- while (_tables[hashi]._state == EXIST)
- {
- ++i;
- hashi = start + i * i;
- hashi %= _tables.size();
- }
- _tables[hashi]._kv = kv;
- _tables[hashi]._state = EXIST;
- ++_size;
-
- return true;
- }
开散列概念
开散列法又叫链地址法(拉链法/哈希桶),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链
接起来,各链表的头结点存储在哈希表中。
哈希桶简单实现:
- template<class K>
- struct HashFunc
- {
- size_t operator()(const K& key)
- {
- return (size_t)key;
- }
- };
-
- //特化
- template<>
- struct HashFunc
- {
- size_t operator()(const string& key)
- {
- size_t val = 0;
- for (auto ch : key)
- {
- //防止出现abc = cba 这种情况,有大佬提出加每个字符前*131
- val *= 131;
- val += ch;
- }
- return val;
- }
- };
-
- namespace HashBucket
- {
- template<class K, class V>
- struct HashNode
- {
- pair
_kv; - HashNode
* _next; -
- HashNode(const pair
& kv) - :_kv(kv)
- ,_next(nullptr)
- {}
- };
-
- template<class K,class V, class Hash = HashFunc
> - class HashTable
- {
- typedef HashNode
Node; - public:
- ~HashTable()
- {
- for (size_t i = 0; i < _tables.size(); ++i)
- {
- Node* cur = _tables[i];
- while (cur)
- {
- Node* next = cur->_next;
- delete cur;
- cur = next;
- }
- _tables[i] = nullptr;
- }
- }
-
- bool Insert(const pair
& kv) - {
- //去重
- if (Find(kv.first))
- {
- return false;
- }
- Hash hash;
- //负载因子到1就扩容
- if (_size == _tables.size())
- {
- size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
- vector
newTables; - newTables.resize(newSize, nullptr);
- //旧表中节点移动映射到新表
- for (size_t i = 0; i < _tables.size(); ++i)
- {
- Node* cur = _tables[i];
- while (cur)
- {
- Node* next = cur->_next;
-
- size_t hashi = hash(cur->_kv.first) % newTables.size();
- cur->_next = newTables[hashi];
- newTables[hashi] = cur;
-
- cur = next;
- }
- _tables[i] = nullptr;
- }
- _tables.swap(newTables);
- }
-
- size_t hashi = hash(kv.first) % _tables.size();
- //头插
- Node* newnode = new Node(kv);
- newnode->_next = _tables[hashi];
- _tables[hashi] = newnode;
- ++_size;
-
- return true;
- }
- Node* Find(const K& key)
- {
- if (_tables.size() == 0)
- {
- return nullptr;
- }
-
- Hash hash;
- size_t hashi = hash(key) % _tables.size();
- Node* cur = _tables[hashi];
- while (cur)
- {
- if (cur->_kv.first == key)
- {
- return cur;
- }
- cur = cur->_next;
- }
- return nullptr;
- }
-
- bool Erase(const K& key)
- {
- if (_tables.size() == 0)
- {
- return false;
- }
-
- Hash hash;
- size_t hashi = hash(key) % _tables.size();
- Node* prev = nullptr;
- Node* cur = _tables[hashi];
- while (cur)
- {
- if (cur->_kv.first == key)
- {
- // 1、头删
- // 2、中间删
- if (prev == nullptr)
- {
- _tables[hashi] = cur->_next;
- }
- else
- {
- prev->_next = cur->_next;
- }
-
- delete cur;
- --_size;
- return true;
- }
-
- prev = cur;
- cur = cur->_next;
- }
-
- return false;
- }
-
- size_t Size()
- {
- return _size;
- }
-
- // 表的长度
- size_t TablesSize()
- {
- return _tables.size();
- }
-
- // 桶的个数
- size_t BucketNum()
- {
- size_t num = 0;
- for (size_t i = 0; i < _tables.size(); ++i)
- {
- if (_tables[i])
- {
- ++num;
- }
- }
-
- return num;
- }
-
- size_t MaxBucketLenth()
- {
- size_t maxLen = 0;
- for (size_t i = 0; i < _tables.size(); ++i)
- {
- size_t len = 0;
- Node* cur = _tables[i];
- while (cur)
- {
- ++len;
- cur = cur->_next;
- }
-
- //if (len > 0)
- //printf("[%d]号桶长度:%d\n", i, len);
-
- if (len > maxLen)
- {
- maxLen = len;
- }
- }
-
- return maxLen;
- }
- private:
- vector
_tables; - size_t _size = 0;//存储有效数据个数
- };
- }
简单修改上述哈希桶用于封装实现unorder_map和unorder_set.
首先,我们将原来节点中用来存储节点值的 pair键值对 改为 模板参数 T.
-
- // 因为关联式容器中存储的是
的键值对,因此 - // k为key的类型,
- // T: 如果是map,则为pair
; 如果是set,则为k - // KeyOfT: 通过T来获取key的一个仿函数类
- namespace Bucket
- {
- template<class T>
- struct HashNode
- {
- T _data;
- HashNode
* _next; -
- HashNode(const T& data)
- :_data(data)
- ,_next(nullptr)
- {}
- };
-
- template<class K,class T, class Hash, class KeyOfT>
- class HashTable
- {
- typedef HashNode
Node; - public:
- ~HashTable()
- {
- for (size_t i = 0; i < _tables.size(); ++i)
- {
- Node* cur = _tables[i];
- while (cur)
- {
- Node* next = cur->_next;
- delete cur;
- cur = next;
- }
- _tables[i] = nullptr;
- }
- }
-
- bool Insert(const T& data)
- {
- Hash hash;
- KeyOfT kot;
- //去重
- if (Find(kot(data)))
- {
- return false;
- }
- //负载因子到1就扩容
- if (_size == _tables.size())
- {
- size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
- vector
newTables; - newTables.resize(newSize, nullptr);
- //旧表中节点移动映射到新表
- for (size_t i = 0; i < _tables.size(); ++i)
- {
- Node* cur = _tables[i];
- while (cur)
- {
- Node* next = cur->_next;
-
- size_t hashi = hash(kot(cur->_data)) % newTables.size();
- cur->_next = newTables[hashi];
- newTables[hashi] = cur;
-
- cur = next;
- }
- _tables[i] = nullptr;
- }
- _tables.swap(newTables);
- }
-
- size_t hashi = hash(kot(data)) % _tables.size();
- //头插
- Node* newnode = new Node(data);
- newnode->_next = _tables[hashi];
- _tables[hashi] = newnode;
- ++_size;
-
- return true;
- }
- Node* Find(const K& key)
- {
- if (_tables.size() == 0)
- {
- return nullptr;
- }
-
- Hash hash;
- KeyOfT kot;
- size_t hashi = hash(key) % _tables.size();
- Node* cur = _tables[hashi];
- while (cur)
- {
- if (kot(cur->_data) == key)
- {
- return cur;
- }
- cur = cur->_next;
- }
- return nullptr;
- }
-
- bool Erase(const K& key)
- {
- if (_tables.size() == 0)
- {
- return false;
- }
-
- KeyOfT kot;
- Hash hash;
- size_t hashi = hash(key) % _tables.size();
- Node* prev = nullptr;
- Node* cur = _tables[hashi];
- while (cur)
- {
- if (kot(cur->_data) == key)
- {
- // 1、头删
- // 2、中间删
- if (prev == nullptr)
- {
- _tables[hashi] = cur->_next;
- }
- else
- {
- prev->_next = cur->_next;
- }
-
- delete cur;
- --_size;
- return true;
- }
-
- prev = cur;
- cur = cur->_next;
- }
-
- return false;
- }
-
- size_t Size()
- {
- return _size;
- }
-
- // 表的长度
- size_t TablesSize()
- {
- return _tables.size();
- }
-
- // 桶的个数
- size_t BucketNum()
- {
- size_t num = 0;
- for (size_t i = 0; i < _tables.size(); ++i)
- {
- if (_tables[i])
- {
- ++num;
- }
- }
-
- return num;
- }
-
- size_t MaxBucketLenth()
- {
- size_t maxLen = 0;
- for (size_t i = 0; i < _tables.size(); ++i)
- {
- size_t len = 0;
- Node* cur = _tables[i];
- while (cur)
- {
- ++len;
- cur = cur->_next;
- }
-
- //if (len > 0)
- //printf("[%d]号桶长度:%d\n", i, len);
-
- if (len > maxLen)
- {
- maxLen = len;
- }
- }
-
- return maxLen;
- }
- private:
- vector
_tables; - size_t _size = 0;//存储有效数据个数
- };
- }
- #include"HashTable.h"//HashTable.h即为上面哈希桶的实现
-
- namespace zj
- {
- template<class K, class V, class Hash = HashFunc
> - class unorder_map
- {
- struct MapKeyOfT
- {
- const K& operator()(const pair
& kv) - {
- return kv.first;
- }
- };
- public:
- bool Insert(const pair
& kv) - {
- return _ht.Insert(kv);
- }
- private:
- Bucket::HashTable
, Hash, MapKeyOfT> _ht; - };
- }
- #include"HashTable.h"//HashTable.h即为上面哈希桶的实现
-
- namespace zj
- {
- template<class K, class Hash = HashFunc
> - class unorder_set
- {
- struct SetKeyOfT
- {
- const K& operator()(const K& key)
- {
- return key;
- }
- };
- public:
- bool Insert(const K& key)
- {
- return _ht.Insert(key);
- }
- private:
- Bucket::HashTable
_ht; - };
- }
3.3 哈希桶迭代器模板
- namespace Bucket
- {
- template<class T>
- struct HashNode
- {
- T _data;
- HashNode
* _next; -
- HashNode(const T& data)
- :_data(data)
- ,_next(nullptr)
- {}
- };
- //前置声明,不然__HashIterator里定义不了_pht
- template<class K, class T, class Hash, class KeyOfT>
- class HashTable;
-
- template<class K, class T, class Hash, class KeyOfT>
- struct __HashIterator
- {
- typedef HashNode
Node; - typedef HashTable
HT; - typedef __HashIterator
Self; -
- Node* _node;
- HT* _pht;
-
- __HashIterator(Node* node, HT* pht)
- :_node(node)
- ,_pht(pht)
- {}
-
- T& operator*()
- {
- return _node->_data;
- }
-
- T* operator->()
- {
- return &_node->_data;
- }
-
- Self& operator++()
- {
- if (_node->_next)
- {
- // 当前桶中迭代
- _node = _node->_next;
- }
- else
- {
- // 找下一个桶
- Hash hash;
- KeyOfT kot;
- size_t i = hash(kot(_node->_data)) % _pht->_tables.size();
- ++i;
- for (; i < _pht->_tables.size(); ++i)
- {
- if (_pht->_tables[i])
- {
- _node = _pht->_tables[i];
- break;
- }
- }
-
- // 说明后面没有有数据的桶了
- if (i == _pht->_tables.size())
- {
- _node = nullptr;
- }
- }
-
- return *this;
- }
-
- bool operator!=(const Self& s) const
- {
- return _node != s._node;
- }
-
- bool operator==(const Self& s) const
- {
- return _node == s._node;
- }
- };
-
- template<class K,class T, class Hash, class KeyOfT>
- class HashTable
- {
- typedef HashNode
Node; -
- template<class K, class T, class Hash, class KeyOfT>//模板参数友元要带声明
- friend struct __HashIterator;
- public:
- typedef __HashIterator
iterator; -
- iterator begin()
- {
- for (size_t i = 0; i < _tables.size(); ++i)
- {
- if (_tables[i])
- {
- return iterator(_tables[i], this);
- }
- }
-
- return end();
- }
-
- iterator end()
- {
- return iterator(nullptr, this);
- }
-
- ~HashTable()
- {
- for (size_t i = 0; i < _tables.size(); ++i)
- {
- Node* cur = _tables[i];
- while (cur)
- {
- Node* next = cur->_next;
- delete cur;
- cur = next;
- }
- _tables[i] = nullptr;
- }
- }
-
- pair
bool > Insert(const T& data) - {
- Hash hash;
- KeyOfT kot;
-
- // 去重
- iterator ret = Find(kot(data));
- if (ret != end())
- {
- return make_pair(ret, false);
- }
-
- //负载因子到1就扩容
- if (_size == _tables.size())
- {
- size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
- vector
newTables; - newTables.resize(newSize, nullptr);
- //旧表中节点移动映射到新表
- for (size_t i = 0; i < _tables.size(); ++i)
- {
- Node* cur = _tables[i];
- while (cur)
- {
- Node* next = cur->_next;
-
- size_t hashi = hash(kot(cur->_data)) % newTables.size();
- cur->_next = newTables[hashi];
- newTables[hashi] = cur;
-
- cur = next;
- }
- _tables[i] = nullptr;
- }
- _tables.swap(newTables);
- }
-
- size_t hashi = hash(kot(data)) % _tables.size();
- //头插
- Node* newnode = new Node(data);
- newnode->_next = _tables[hashi];
- _tables[hashi] = newnode;
- ++_size;
-
- return make_pair(iterator(newnode, this), true);
- }
- iterator Find(const K& key)
- {
- if (_tables.size() == 0)
- {
- return end();
- }
-
- Hash hash;
- KeyOfT kot;
- size_t hashi = hash(key) % _tables.size();
- Node* cur = _tables[hashi];
- while (cur)
- {
- if (kot(cur->_data) == key)
- {
- return iterator(cur, this);
- }
- cur = cur->_next;
- }
- return end();
- }
-
- bool Erase(const K& key)
- {
- if (_tables.size() == 0)
- {
- return false;
- }
-
- KeyOfT kot;
- Hash hash;
- size_t hashi = hash(key) % _tables.size();
- Node* prev = nullptr;
- Node* cur = _tables[hashi];
- while (cur)
- {
- if (kot(cur->_data) == key)
- {
- // 1、头删
- // 2、中间删
- if (prev == nullptr)
- {
- _tables[hashi] = cur->_next;
- }
- else
- {
- prev->_next = cur->_next;
- }
-
- delete cur;
- --_size;
- return true;
- }
-
- prev = cur;
- cur = cur->_next;
- }
-
- return false;
- }
-
- ....
-
- private:
- vector
_tables; - size_t _size = 0;//存储有效数据个数
- };
-
- }
- #include"HashTable.h"
-
- namespace zj
- {
- template<class K, class V, class Hash = HashFunc
> - class unordered_map
- {
- struct MapKeyOfT
- {
- const K& operator()(const pair
& kv) - {
- return kv.first;
- }
- };
- public:
- typedef typename Bucket::HashTable
, Hash, MapKeyOfT>::iterator iterator; -
- iterator begin()
- {
- return _ht.begin();
- }
-
- iterator end()
- {
- return _ht.end();
- }
-
- pair
bool > Insert(const pair& kv) - {
- return _ht.Insert(kv);
- }
-
- V& operator[](const K& key)
- {
- pair
bool> ret = _ht.Insert(make_pair(key, V())); - return ret.first->second;
- }
- private:
- Bucket::HashTable
, Hash, MapKeyOfT> _ht; - };
-
- void test_map()
- {
- unordered_map
dict; - dict.Insert(make_pair("sort", ""));
- dict.Insert(make_pair("string", ""));
- dict.Insert(make_pair("left", ""));
-
- unordered_map
::iterator it = dict.begin(); - while (it != dict.end())
- {
- cout << it->first << ":" << it->second << endl;
- ++it;
- }
- cout << endl;
-
- }
- }
- #include"HashTable.h"
-
- namespace zj
- {
- template<class K, class Hash = HashFunc
> - class unorder_set
- {
- struct SetKeyOfT
- {
- const K& operator()(const K& key)
- {
- return key;
- }
- };
- public:
- typedef typename Bucket::HashTable
::iterator iterator; -
- iterator begin()
- {
- return _ht.begin();
- }
-
- iterator end()
- {
- return _ht.end();
- }
-
- pair
bool > Insert(const K& key) - {
- return _ht.Insert(key);
- }
- private:
- Bucket::HashTable
_ht; - };
-
- void test_set()
- {
- unordered_set<int> s;
- s.insert(2);
- s.insert(3);
- s.insert(1);
- s.insert(2);
- s.insert(5);
-
- unordered_set<int>::iterator it = s.begin();
- //auto it = s.begin();
- while (it != s.end())
- {
- cout << *it << " ";
- ++it;
- }
- cout << endl;
- }
- }