赞
踩
需要云服务器等云产品来学习Linux的同学可以移步/-->腾讯云<--/-->阿里云<--/-->华为云<--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。
目录
八、使用开散列对unordered_set和unordered_map就行封装
在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到logN,最差情况下也仅需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。因此在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同,unordered系列容器并不是有序的。
树状关联式容器对key的要求是比较大小,哈希对key的要求是转成整型,用于取模。它们都是通过仿函数来实现的。
unordered_set并不像set那样支持反向迭代器,它的迭代器底层是一个单向迭代器。 其他功能与set类似。
unordered_set的插入是无序的,不一定按照插入的顺序进行打印。自带去重功能。
单向迭代器+无序。其他功能与map类似。
红黑树的插入删除查找性能都是O(logN)而哈希表的插入删除查找性能理论上都是O(1),他是相对于稳定的,最差情况下都是高效的。哈希表的插入删除操作的理论上时间复杂度是常数时间的,这有个前提就是哈希表不发生数据碰撞。在发生碰撞的最坏的情况下,哈希表的插入和删除时间复杂度为O(n)。
顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码的多次比较。顺序查找时间复杂度为O(N),平衡树中为树的高度,即O(logN),搜索的效率取决于搜索过程中元素的比较次数。
理想的搜索方法:那么可以不经过任何比较,一次直接从表中得到想要搜索的元素?
如果构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。在哈希表中插入或查找的方法就叫做哈希函数。
1. 直接定址法--(常用)
取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B
优点:简单、均匀
缺点:需要事先知道关键字的分布情况
使用场景:适合查找比较小且连续的情况(范围集中)
2. 除留余数法--(常用)
设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,
按照哈希函数:Hash(key) = key% p(p<=m),将关键码转换成哈希地址
缺点:可能会存在哈希冲突(哈希碰撞)
哈希函数:1、闭散列(开放定址法)2、开散列(拉链法/哈希桶)
18模10应将18放在数组下标为8的位置。8模10也应当将8放在数组下标为8的位置,但是这个坑位已经被18占了,此时发生哈希冲突,需要将8放在18的后面,8一直往后找,哪个位置没人就放在哪个位置。
但是每一个坑位其实有三种状态:坑位为空、坑位不为空、坑位是一个被删除的数据。
现在需要删除27,只需要找到27并将其状态标志位修改为删除状态即可,并不用真正的清除数据,但要注意的是,27的值还在,我们再次对27进行查找,需要先判断27的标志位,不然27明明删掉了,你还说找到了,那就离谱了。
对于线性探测,是不会让这个数组处于充满的状态,需要控制负载因子保证数组长期处于相对恒定的充满率。
负载因子=表中有效数据的个数/表的大小。负载因子越大,虽然空间利用率越高,但下一次插入时发生哈希冲突的概率越高!
如何扩容:因为扩容后,表的大小变大,根据映射公式hashi=key%tablesize,整个数组的映射关系全部被改变,所以扩容时,需要将原有数据一个一个的重新映射进新数组。
size_t hashi = hf(kv.first) % _tables.size();
哈希的核心就是取模,所以key需要能够被取模。一般来说,哈希的key都是整型或字符串,所以这里写了两个仿函数来将外部类型转换为size_t和string类型。
如果使用其他自定义类型充当key,需要自己仿函数,传入哈希。
- template <class K, class V>
- struct HashData//存储哈希的数据
- {
- std::pair<K, V> _kv;//存储节点的数据
- State _state = EMPTY;//节点的状态
- };
- template <class K>
- struct HashFunc//仿函数,控制hashi取模操作,把相近类型转为整型
- {
- size_t operator()(const K& key)
- {
- return (size_t)key;
- }
- };
- template <>//模板的特化
- struct HashFunc<string>
- {
- size_t operator()(const std::string& key)
- {
- size_t hash = 0;//通过格式计算string的值
- //for (auto& ch : key)//直接相加哈希冲突概率大
- //{
- // hash += ch;
- //}
- for (auto& ch : key)
- {
- hash = hash * 31 + ch;//也可以乘31,131,1313,13131,131313
- }
- return hash;
- }
- };

对于string类型转整形,不能单纯的使用字符相加的方式进行转换,因为“abc”和“acb”依照字符串相加后的整型值是一样的,这就造成了哈希冲突。下面是一个大佬设计BKDR哈希算法,极大地降低了哈希冲突。
原文链接:各种字符串哈希函数
线性探测是(加0,加1,加2,加3),而二次探测就是
(加0,加1,加4,加9)
当然二次探测同样没有从本质上解决问题,还是存在占别人坑位的情况。于是就提出了开散列(哈希桶)。
unorder系统列的底层用的就是开散列。
开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。
官方文档中规定开散列的负载因子是1,负载因子是1的意思是当哈希表的size等于节点数量时,就需要扩容了。
- if(_tables.size()==_n)
- {
- //HashTable<K, V> newHT;
- //newHT._tables.resize(_tables.size() * 2);
- //for (auto& cur : _tables)//遍历表,不为空说明有桶
- //{
- // while (cur)
- // {
- // 依次取出旧表的数据插入新表
- // newHT.Insert(cur->_kv);
- // cur = cur->_next;
- // }
- //}
- //_tables.swap(newHT._tables);
- std::vector<Node*> newtables;
- newtables.resize(2 * _tables.size(), 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);
- }

- ~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;
- }
- }
这里是两种扩容写法,注释掉的那一种是把原表的节点拷贝一份插入到新的哈希表,全部元素映射完毕后再交换哈希表。未注释的那种写法是通过修改哈希桶中单链表的指针指向,直接摘取原表元素,同样映射完毕后交换哈希表,没有拷贝构造的过程。不过用的时候记得将原表中的指向置空,否则藕断丝连,原表被交换后会发生析构,因为指向关系没有断,造成刚插入的数据全部被清空。
为啥闭散列不能必须老老实实的拷贝?因为闭散列中的哈希表存的是值,开散列中存的是节点,节点可以摘下来,值不能摘啊。
扩容时不一定是两倍,为了一定程度上缓解哈希冲突,stl底层给了扩容的数组大小,均为素数且近似两倍。不过别人拿到你的扩容源码,可以专门设置一组连续冲突的数据来恶心你(比如力扣刷题你用unordered系列。。。)。
当哈希桶的节点挂载过多时,查找效率逐渐变低,像Java会在哈希桶节点数大于8时,将哈希桶的底层由单链表切换为红黑树。
- #pragma once
- #include <iostream>
- #include <vector>
- template <class K>
- struct HashFunc//仿函数,控制hashi取模操作,把相近类型转为整型
- {
- size_t operator()(const K& key)
- {
- return (size_t)key;
- }
- };
- template <>//模板的特化
- struct HashFunc < std::string >
- {
- size_t operator()(const std::string& key)
- {
- size_t hash = 0;//通过格式计算string的值
- //for (auto& ch : key)//直接相加哈希冲突概率大
- //{
- // hash += ch;
- //}
- for (auto& ch : key)
- {
- hash = hash * 31 + ch;//也可以乘31,131,1313,13131,131313
- }
- return hash;
- }
- };
- namespace closeHash
- {
- enum State
- {
- EMPTY,
- EXIST,
- DELTE
- };
- template <class K, class V>
- struct HashData//存储哈希的数据
- {
- std::pair<K, V> _kv;//存储节点的数据
- State _state = EMPTY;//节点的状态
- };
- template <class K, class V, class Hash = HashFunc<K>>//Hash:把key转换为可以取模的整型
- class HashTable
- {
- typedef HashData<K, V> Data;
- public:
- HashTable()
- :_n(10)
- {
- _tables.resize(10);
- }
- bool Insert(const std::pair<K, V>& kv)
- {
- if (Find(kv.first) != nullptr)
- return false;
- //大于标定的负载因子,就扩容
- if (_n * 10 >= 7 * _tables.size())
- {
- HashTable<K, V> newHT;
- newHT._tables.resize(_tables.size() * 2);
- for (auto& e : _tables)
- {
- if (e._state == EXIST)
- {
- newHT.Insert(e._kv);
- }
- }
- _tables.swap(newHT._tables);
- }
- Hash hf;
- size_t hashi = hf(kv.first) % _tables.size();//找到首先要插入的位置。如果kv.first是string呢?如何取模?
- while (_tables[hashi]._state == EXIST) //先将string转化为整数,再进行取模操作?应该用仿函数
- {
- ++hashi;//线性探测
- hashi %= _tables.size();
-
- }
- //走到这里就是删除或空
- _tables[hashi]._kv = kv;
- _tables[hashi]._state = EXIST;
- ++_n;
- return true;
- }
- Data* Find(const K& key)
- {
- Hash hf;
- size_t hashi = hf(key) % _tables.size();
- while (_tables[hashi]._state != EMPTY)/
- {
- if (_tables[hashi]._state == EXIST && _tables[hashi]._kv.first == key)//存在且为key
- return &_tables[hashi];
- else
- ++hashi;
- hashi %= _tables.size();
- }
- return nullptr;
- }
- bool Erase(const K& key)
- {
- Data* ret = Find(key);
- if (ret != nullptr)
- {
- ret->_state = DELTE;
- --_n;
- return true;
- }
- return false;
- }
- private:
- std::vector<Data> _tables;
- size_t _n = 0;//表中存储的有效数据的个数
- };
- void HashTest()
- {
- HashTable<int, int> ht;
- int a[] = { 18,8,7,27,57,3,38,18 };
- for (auto& e : a)
- {
- ht.Insert(std::make_pair(e, e));
- }
- ht.Insert(std::make_pair(17, 17));
- ht.Insert(std::make_pair(5, 5));
-
- std::cout << ht.Find(7) << std::endl;
- std::cout << ht.Find(8) << std::endl;
- ht.Erase(7);
- std::cout << ht.Find(7) << std::endl;
- std::cout << ht.Find(8) << std::endl;
- }
- }
- namespace buckets
- {
- template<class K, class V>
- struct HashNode
- {
- std::pair<K, V> _kv;
- HashNode<K, V>* _next;
-
- HashNode(const std::pair<K,V>& kv)
- :_kv(kv)
- , _next(nullptr)
- {}
-
- };
- template <class K, class V, class Hash = HashFunc<K>>
- class HashTable
- {
- typedef HashNode<K, V> Node;
- public:
- HashTable()
- :_n(0)
- {
- _tables.resize(__stl_next_prime(0));
- }
- ~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 std::pair<K, V>& kv)
- {
- if (Find(kv.first))
- return false;
- //负载因子控制在1,超过就扩容
- if(_tables.size()==_n)
- {
- //HashTable<K, V> newHT;
- //newHT._tables.resize(_tables.size() * 2);
- //for (auto& cur : _tables)//遍历表,不为空说明有桶
- //{
- // while (cur)
- // {
- // 依次取出旧表的数据插入新表
- // newHT.Insert(cur->_kv);
- // cur = cur->_next;
- // }
- //}
- //_tables.swap(newHT._tables);
- std::vector<Node*> newtables;
- //newtables.resize(2 * _tables.size(), nullptr);//不是2倍扩容
- newtables.resize(__stl_next_prime(_tables.size()), 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]存的是第一个元素的地址
- _tables[hashi] = newNode;
- ++_n;
- return true;
- }
- Node* Find(const K& key)
- {
- size_t hashi = Hash()(key) % _tables.size();
- Node* cur = _tables[hashi];
- while (cur)
- {
- if (cur->_kv.first != key)
- {
- cur = cur->_next;
- }
- else
- return cur;
- }
- return nullptr;
- }
- bool Erase(const K& key)
- {
- size_t hashi = Hash()(key) % _tables.size();
- Node* cur = _tables[hashi];
- Node* prev = nullptr;
- while (cur)
- {
-
- Node* next = cur->_next;
- if (cur->_kv.first == key)
- {
- delete cur;
- if (prev == nullptr)
- {
- _tables[hashi] = next;
- }
- else
- {
- prev->_next = next;
- }
- --_n;
- return true;
- }
- prev = cur;
- cur = next;
- }
- return false;
- }
- inline unsigned long __stl_next_prime(unsigned long n)
- {
- 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, 3221225473, 4294967291
- };
-
- for (int i = 0; i < __stl_num_primes; ++i)
- {
- if (__stl_prime_list[i] > n)
- {
- return __stl_prime_list[i];
- }
- }
-
- return __stl_prime_list[__stl_num_primes - 1];//否则返回设定的最大值,够用了
- }
- private:
- std::vector<Node*> _tables;//需要写析构,释放单链表的节点
- size_t _n = 0;
- };
- void HashTest()
- {
- HashTable<int, int> ht;
- int a[] = { 18,8,7,27,57,3,38,18 ,17,88,38,28,48 };
- for (auto& e : a)
- {
- ht.Insert(std::make_pair(e, e));
- }
- ht.Insert(std::make_pair(5, 5));
- ht.Erase(5);
- }
- }

- #pragma once
- #include <iostream>
- #include <vector>
- template <class K>
- struct HashFunc//仿函数,控制hashi取模操作,把相近类型转为整型
- {
- size_t operator()(const K& key)
- {
- return (size_t)key;
- }
- };
- template <>//模板的特化
- struct HashFunc < std::string >
- {
- size_t operator()(const std::string& key)
- {
- size_t hash = 0;//通过格式计算string的值
- //for (auto& ch : key)//直接相加哈希冲突概率大
- //{
- // hash += ch;
- //}
- for (auto& ch : key)
- {
- hash = hash * 31 + ch;//也可以乘31,131,1313,13131,131313
- }
- return hash;
- }
- };
- namespace closeHash
- {
- enum State
- {
- EMPTY,
- EXIST,
- DELTE
- };
- template <class K, class V>
- struct HashData//存储哈希的数据
- {
- std::pair<K, V> _kv;//存储节点的数据
- State _state = EMPTY;//节点的状态
- };
- template <class K, class V, class Hash = HashFunc<K>>//Hash:把key转换为可以取模的整型
- class HashTable
- {
- typedef HashData<K, V> Data;
- public:
- HashTable()
- :_n(10)
- {
- _tables.resize(10);
- }
- bool Insert(const std::pair<K, V>& kv)
- {
- if (Find(kv.first) != nullptr)
- return false;
- //大于标定的负载因子,就扩容
- if (_n * 10 >= 7 * _tables.size())
- {
- HashTable<K, V> newHT;
- newHT._tables.resize(_tables.size() * 2);
- for (auto& e : _tables)
- {
- if (e._state == EXIST)
- {
- newHT.Insert(e._kv);
- }
- }
- _tables.swap(newHT._tables);
- }
- Hash hf;
- size_t hashi = hf(kv.first) % _tables.size();//找到首先要插入的位置。如果kv.first是string呢?如何取模?
- while (_tables[hashi]._state == EXIST) //先将string转化为整数,再进行取模操作?应该用仿函数
- {
- ++hashi;//线性探测
- hashi %= _tables.size();
-
- }
- //走到这里就是删除或空
- _tables[hashi]._kv = kv;
- _tables[hashi]._state = EXIST;
- ++_n;
- return true;
- }
- Data* Find(const K& key)
- {
- Hash hf;
- //size_t hashi = hf(key) % _tables.size();
- size_t starti=hashi;
- while (_tables[hashi]._state != EMPTY)/
- {
- if (_tables[hashi]._state == EXIST && _tables[hashi]._kv.first == key)//存在且为key
- return &_tables[hashi];
- else
- ++hashi;
- hashi %= _tables.size();
- //极端场景下,没有空,全是存在或删除状态
- if(hashi==starti)
- {
- break;
- }
- }
- return nullptr;
- }
- bool Erase(const K& key)
- {
- Data* ret = Find(key);
- if (ret != nullptr)
- {
- ret->_state = DELTE;
- --_n;
- return true;
- }
- return false;
- }
- private:
- std::vector<Data> _tables;
- size_t _n = 0;//表中存储的有效数据的个数
- };
- void HashTest()
- {
- HashTable<int, int> ht;
- int a[] = { 18,8,7,27,57,3,38,18 };
- for (auto& e : a)
- {
- ht.Insert(std::make_pair(e, e));
- }
- ht.Insert(std::make_pair(17, 17));
- ht.Insert(std::make_pair(5, 5));
-
- std::cout << ht.Find(7) << std::endl;
- std::cout << ht.Find(8) << std::endl;
- ht.Erase(7);
- std::cout << ht.Find(7) << std::endl;
- std::cout << ht.Find(8) << std::endl;
- }
- }
- namespace buckets
- {
- template<class T>
- struct HashNode
- {
- //std::pair<K, V> _kv;
- T _data;
- HashNode<T>* _next;
-
- HashNode(const T& data)
- :_data(data)
- , _next(nullptr)
- {}
-
- };
- //哈希表引用迭代器,迭代器引用哈希表的类型,相互引用,需要先前置声明
- template <class K, class T, class Hash, class KeyOfT>
- class HashTable;
- template <class K, class T, class Hash, class KeyOfT>
- struct __HTIterator
- {
- typedef HashNode<T> Node;
- typedef __HTIterator<K, T, Hash,KeyOfT> Self;
- typedef HashTable<K, T, Hash, KeyOfT> HT;
- Node* _node;
- HT* _ht;
- __HTIterator(Node* node,HT* ht)
- :_node(node)
- ,_ht(ht)
- {}
- Self& operator++()
- {
- if (_node->_next)
- {
- _node = _node->_next;
- }
- else//当前桶走完了,需要找下一个桶
- {
- KeyOfT kot;
- Hash hash;
- size_t hashi = hash(kot(_node->_data))%(_ht->_tables.size());//等价于Hash()(KeyOfT()(_node->_data))
- ++hashi;//因为迭代器++是找下一个元素,这个桶走完了,跳过当前hashi
- while (hashi<_ht->_tables.size())//如果hashi没越界
- {
- if (_ht->_tables[hashi]) //哈希表不为空
- {
- _node = _ht->_tables[hashi];
- break;
- }
- ++hashi;
- }
- //说明没有桶了,找完了找不到
- if (hashi == _ht->_tables.size())
- _node = nullptr;
- }
- return *this;
- }
- T& operator*()
- {
- return _node->_data;
- }
- T* operator->()
- {
- return &(_node->_data);
- }
- bool operator!=(const Self& it)const
- {
- return _node != it._node;
- }
-
- };
- template <class K, class T, class Hash,class KeyOfT>
- class HashTable
- {
- template <class K, class T, class Hash, class KeyOfT>
- friend struct __HTIterator;
- typedef HashNode<T> Node;
- public:
- typedef __HTIterator<K, T, Hash, KeyOfT> iterator;
- iterator begin()
- {
- for (size_t i = 0; i < _tables.size(); ++i)
- {
- if (_tables[i] != nullptr)
- return iterator(_tables[i], this);
- }
- return iterator(nullptr, this);
- }
- iterator end()
- {
- return iterator(nullptr, this);
- }
- HashTable()
- :_n(0)
- {
- _tables.resize(__stl_next_prime(0));
- }
- ~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;
- }
- }
- std::pair<iterator,bool> Insert(const T& data)
- {
- KeyOfT kot;
- iterator it = Find(kot(data));
- if (it!=end())//说明找到了相同元素。返回false
- return std::make_pair(it,false);
- //负载因子控制在1,超过就扩容
- if(_tables.size()==_n)
- {
- //HashTable<K, V> newHT;
- //newHT._tables.resize(_tables.size() * 2);
- //for (auto& cur : _tables)//遍历表,不为空说明有桶
- //{
- // while (cur)
- // {
- // 依次取出旧表的数据插入新表
- // newHT.Insert(cur->_kv);
- // cur = cur->_next;
- // }
- //}
- //_tables.swap(newHT._tables);
- std::vector<Node*> newtables;
- //newtables.resize(2 * _tables.size(), nullptr);//不是2倍扩容
- newtables.resize(__stl_next_prime(_tables.size()), 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]存的是第一个元素的地址
- _tables[hashi] = newNode;
- ++_n;
- return std::make_pair(iterator(newNode,this),true);
- }
- iterator Find(const K& key)
- {
- KeyOfT kot;
- size_t hashi = Hash()(key) % _tables.size();
- Node* cur = _tables[hashi];
- while (cur)
- {
- if (kot(cur->_data) != key)
- {
- cur = cur->_next;
- }
- else
- return iterator(cur,this);
- }
- return iterator(nullptr,this);
- }
- bool Erase(const K& key)
- {
- size_t hashi = Hash()(key) % _tables.size();
- Node* cur = _tables[hashi];
- Node* prev = nullptr;
- while (cur)
- {
-
- Node* next = cur->_next;
- if (cur->_kv.first == key)
- {
- delete cur;
- if (prev == nullptr)
- {
- _tables[hashi] = next;
- }
- else
- {
- prev->_next = next;
- }
- --_n;
- return true;
- }
- prev = cur;
- cur = next;
- }
- return false;
- }
- inline unsigned long __stl_next_prime(unsigned long n)
- {
- 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, 3221225473, 4294967291
- };
-
- for (int i = 0; i < __stl_num_primes; ++i)
- {
- if (__stl_prime_list[i] > n)
- {
- return __stl_prime_list[i];
- }
- }
-
- return __stl_prime_list[__stl_num_primes - 1];//否则返回设定的最大值,够用了
- }
- private:
- std::vector<Node*> _tables;//需要写析构,释放单链表的节点
- size_t _n = 0;
- };
- /*void HashTest()
- {
- HashTable<int, int> ht;
- int a[] = { 18,8,7,27,57,3,38,18 ,17,88,38,28,48 };
- for (auto& e : a)
- {
- ht.Insert(std::make_pair(e, e));
- }
- ht.Insert(std::make_pair(5, 5));
- ht.Erase(5);
- }*/
- }

- #pragma once
- #include "HashTable.h"
- namespace jly
- {
- template <class K, class Hash= HashFunc<K>>//K:key;Hash:将key转为整型的仿函数
- class unordered_set
- {
- struct SetKeyOfT
- {
- const K& operator()(const K& key)
- {
- return key;
- }
- };
- public:
- typedef typename buckets::HashTable<K, K,Hash, SetKeyOfT>::iterator iterator;
- iterator begin()
- {
- return _ht.begin();
- }
- iterator end()
- {
- return _ht.end();
- }
- iterator Find(const K& key)
- {
- return _ht.Find(key);
- }
- bool erase(const K& key)
- {
- return _ht.Erase(key);
- }
- std::pair<iterator, bool> Insert(const K& data)
- {
- return _ht.Insert(data);
- }
-
- private:
- buckets::HashTable<K, K,Hash,SetKeyOfT> _ht;
- };
- void test_unordered_set()
- {
- unordered_set<int> us;
- us.Insert(3);
- us.Insert(13);
- us.Insert(23);
- us.Insert(5);
- us.Insert(5);
- us.Insert(6);
- us.Insert(106);
- us.Insert(53);
-
- unordered_set<int>::iterator it = us.begin();
- while (it != us.end())
- {
- std::cout << *it << " ";
- ++it;
- }
- std::cout << std::endl;
- for (auto& e : us)
- {
- std::cout << e << " ";
- }
- }
- }

- #pragma once
- #include "HashTable.h"
- namespace jly
- {
-
- template <class K, class V,class Hash = HashFunc<K>>//Hash:将key转为整型的仿函数
- class unordered_map
- {
- struct MapKeyOfT
- {
- const K& operator()(const std::pair<const K, V>& kv)
- {
- return kv.first;
- }
- };
- public:
- typedef typename buckets::HashTable<K, std::pair<const K, V>, Hash, MapKeyOfT>::iterator iterator;
- std::pair<iterator,bool> Insert(const std::pair<K, V>& data)
- {
- return _ht.Insert(data);
- }
- V& operator[](const K& key)
- {
- std::pair<iterator, bool> ret = _ht.Insert(std::make_pair(key, V()));
- return ret.first->second;
-
- }
- iterator Find(const K& key)
- {
- return _ht.Find(key);
- }
- bool erase(const K& key)
- {
- return _ht.Erase(key);
- }
- iterator begin()
- {
- return _ht.begin();
- }
- iterator end()
- {
- return _ht.end();
- }
- private:
- buckets::HashTable<K, std::pair<const K,V>,Hash, MapKeyOfT> _ht;
- };
- void test_unordered_map()
- {
- std::string arr[] = { "牛奶", "水罐", "冰", "牛奶", "冰", "水罐",
- "冰", "冰", "冰", "木头", "冰", "木头" };
-
- unordered_map<std::string, int> countMap;
- for (auto& e : arr)
- {
- countMap[e]++;
- }
-
- for (const auto& kv : countMap)
- {
- std::cout << kv.first << ":" << kv.second << std::endl;
- }
- }
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。