namespace hash_bucket { template<class K, class V> struct HashNode { pair<K, V> _kv; HashNode<K, V>* _next; HashNode(const pair<K, V>& kv) :_kv(kv) ,_next(nullptr) {} }; template<class K, class V, class Hash = HashFunc<K>> class HashTable { typedef HashNode<K, V> Node; 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 }; 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); return pos == last ? *(last - 1) : *pos; } public: HashTable() { _tables.resize(__stl_next_prime(0), nullptr); } // 拷⻉构造和赋值拷⻉需要实现深拷⻉,有兴趣的同学可以⾃⾏实现 ~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<K, V>& kv) { Hash hs; size_t hashi = hs(kv.first) % _tables.size(); // 负载因⼦==1扩容 if (_n == _tables.size()) { /*HashTable<K, V> newHT; newHT._tables.resize(__stl_next_prime(_tables.size()+1); for (size_t i = 0; i < _tables.size(); i++) { Node* cur = _tables[i]; while(cur) { newHT.Insert(cur->_kv); cur = cur->_next; } } _tables.swap(newHT._tables);*/ // 这⾥如果使⽤上⾯的⽅法,扩容时创建新的结点,后⾯还要使⽤就结 点,浪费了 // 下⾯的⽅法,直接移动旧表的结点到新表,效率更好 vector<Node*> newtables(__stl_next_prime(_tables.size()+1), nullptr); for (size_t i = 0; i < _tables.size(); i++) { Node* cur = _tables[i]; while (cur) { Node* next = cur->_next; // 旧表中节点,挪动新表重新映射的位置 size_t hashi = hs(cur->_kv.first) % newtables.size(); // 头插到新表 cur->_next = newtables[hashi]; newtables[hashi] = cur; cur = next; } _tables[i] = nullptr; } _tables.swap(newtables); } // 头插 Node* newnode = new Node(kv); newnode->_next = _tables[hashi]; _tables[hashi] = newnode; ++_n; return true; } Node* Find(const K& key) { Hash hs; size_t hashi = hs(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) { Hash hs; size_t hashi = hs(key) % _tables .size(); Node* prev = nullptr; Node* cur = _tables[hashi]; while (cur) { if (cur->_kv.first == key) { if (prev == nullptr) { _tables[hashi] = cur->_next; } else { prev->_next = cur->_next; } delete cur; --_n; return true; } prev = cur; cur = cur->_next; } return false; } private: vector<Node*> _tables; // 指针数组 size_t _n = 0; // 表中存储数据个数 }; }
⽤哈希表封装myunordered_map和 myunordered_set
模拟实现unordered_map和unordered_set
#pragma once #include"Hashtable.h" // MyUnorderedMap.h namespace map { template<class K, class V, class Hash = HashFunc<K>> class unordered_map { struct MapKeyOfT { const K& operator()(const pair<K, V>& kv) { return kv.first; } }; public: typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::Iterator iterator; typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::ConstIterator 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(); } V& operator[](const K& key) { pair<iterator, bool> ret = insert({ key, V() }); return ret.first->second; } pair<iterator, bool> insert(const pair<K, V>& kv) { return _ht.Insert(kv); } iterator Find(const K& key) { return _ht.Find(key); } bool Erase(const K& key) { return _ht.Erase(key); } private: hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht; }; void test_map1() { unordered_map<string, string> dict; dict.insert({ "sort", "排序" }); dict.insert({ "字符串", "string" }); dict.insert({ "sort", "排序" }); dict.insert({ "left", "左边" }); dict.insert({ "right", "右边" }); dict["left"] = "左边,剩余"; dict["insert"] = "插入"; dict["string"]; for (auto& kv : dict) { cout << kv.first << ":" << kv.second << endl; } cout << endl; unordered_map<string, string>::iterator it = dict.begin(); while (it != dict.end()) { // 不能修改first,可以修改second //it->first += 'x'; it->second += 'x'; cout << it->first << ":" << it->second << endl; ++it; } cout << endl; } }
#pragma once #include"Hashtable.h" namespace set { template<class K, class Hash = HashFunc<K>> class unordered_set { struct SetKeyOfT { const K& operator()(const K& key) { return key; } }; public: typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::Iterator iterator; typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::ConstIterator 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(); } pair<iterator, bool> insert(const K& key) { return _ht.Insert(key); } iterator Find(const K& key) { return _ht.Find(key); } bool Erase(const K& key) { return _ht.Erase(key); } private: hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht; }; void print(const unordered_set<int>& s) { unordered_set<int>::const_iterator it = s.begin(); while (it != s.end()) { //*it = 1; cout << *it << " "; ++it; } cout << endl; for (auto e : s) { cout << e << " "; } cout << endl; } void test_set1() { int a[] = { 3,11,86,7,88,82,1,881,5,6,7,6 }; unordered_set<int> s; for (auto e : a) { s.insert(e); } unordered_set<int>::iterator it = s.begin(); while (it != s.end()) { //*it = 1; cout << *it << " "; ++it; } cout << endl; for (auto e : s) { cout << e << " "; } cout << endl; print(s); } }
⽀持iterator的实现
#pragma once #include <vector> #include <iostream> #include <string> using namespace std; // 请完成哈希表的如下操作 // 哈希函数采用除留余数法 //template<class K> //struct HashFunc //{ // size_t operator()(const K& key) // { // return (size_t)key; // } //}; // //// 哈希表中支持字符串的操作 //template<> //struct HashFunc<string> //{ // size_t operator()(const string& key) // { // size_t hash = 0; // for (auto e : key) // { // hash *= 31; // hash += e; // } // // return hash; // } //}; // 以下采用开放定址法,即线性探测解决冲突 enum State { EXIST, EMPTY, DELETE }; template<class K, class V> struct HashData { pair<K, V> _kv; State _state = EMPTY; }; template<class K> struct HashFunc { size_t operator()(const K& key) { return (size_t)key; } }; template<> struct HashFunc<string> { size_t operator()(const string& s) { // 补充:常用的BKDR字符串哈希算法(经典且高效) size_t hash = 0; for (char ch : s) { hash = hash + ch; hash = hash * 131;// 131是经验质数,也可用31/13131等 } return hash; } }; inline unsigned long _stl_next_prime(unsigned long n) { // 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] = { 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 }; 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); return pos == last ? *(last - 1) : *pos; } namespace open_address { template<class K, class V, class Hash = HashFunc<K>> class HashTable { public: HashTable() :_tables(_stl_next_prime(0)) , _n(0) {} bool Insert(const pair<K, V>& kv) { if (Find(kv.first)) return false; // 负载因子 >= 0.7扩容 if (_n * 10 / _tables.size() >= 7) { //vector<HashData<K, V>> newtables(_tables.size()*2); //for (auto& data : _tables) //{ // // 旧表的数据映射到新表 // if (data._state == EXIST) // { // size_t hash0 = data._kv.first % newtables.size(); // // ... // } //} //_tables.swap(newtables); HashTable<K, V, Hash> newht; //newht._tables.resize(_tables.size() * 2); newht._tables.resize(__stl_next_prime(_tables.size() + 1)); for (auto& data : _tables) { // 旧表的数据映射到新表 if (data._state == EXIST) { newht.Insert(data._kv); } } _tables.swap(newht._tables); } Hash hash; size_t hash0 = hash(kv.first) % _tables.size(); size_t hashi = hash0; size_t i = 1; int flag = 1; while (_tables[hashi]._state == EXIST) { // 线性探测 hashi = (hash0 + i) % _tables.size(); ++i; /*hashi = (hash0 + (i*i*flag)) % _tables.size(); if (hashi < _tables.size()) hashi += _tables.size(); if (flag == 1) { flag = -1; } else { ++i; flag = 1; }*/ } _tables[hashi]._kv = kv; _tables[hashi]._state = EXIST; ++_n; return true; } HashData<K, V>* Find(const K& key) { Hash hash; size_t hash0 = hash(key) % _tables.size(); size_t hashi = hash0; size_t i = 1; while (_tables[hashi]._state != EMPTY) { if (_tables[hashi]._state == EXIST && _tables[hashi]._kv.first == key) { return &_tables[hashi]; } // 线性探测 hashi = (hash0 + i) % _tables.size(); ++i; } return nullptr; } bool Erase(const K& key) { HashData<K, V>* ret = Find(key); if (ret) { ret->_state = DELETE; return true; } else { return false; } } private: vector<HashData<K, V>> _tables; size_t _n; // 记录数据个数 }; } namespace hash_bucket { template<class T> struct HashNode { T _data; HashNode<T>* _next; HashNode(const T& data) :_data(data) , _next(nullptr) {} }; template<class K, class T, class KeyOfT, class Hash> class HashTable; template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash> struct HTIterator { typedef HashNode<T> Node; typedef HashTable<K, T, KeyOfT, Hash> HT; typedef HTIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self; Node* _node; const HT* _ht; HTIterator(Node* node, const HT* ht) :_node(node) , _ht(ht) {} Ref operator*() { return _node->_data; } Ptr operator->() { return &_node->_data; } bool operator!=(const Self& s) { return _node != s._node; } Self& operator++() { if (_node->_next) { _node = _node->_next; } else { KeyOfT kot; Hash hash; size_t hashi = hash(kot(_node->_data)) % _ht->_tables.size(); ++hashi; while (hashi < _ht->_tables.size()) { _node = _ht->_tables[hashi]; if (_node) break; else ++hashi; } // 所有桶都走完了,end()给的空标识的_node if (hashi == _ht->_tables.size()) { _node = nullptr; } } return *this; } }; // K 为 T 中key的类型 // T 可能是键值对,也可能是K // KeyOfT: 从T中提取key // Hash将key转化为整形,因为哈市函数使用除留余数法 template<class K, class T, class KeyOfT, class Hash> class HashTable { template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash> friend struct HTIterator; typedef HashNode<T> Node; public: typedef HTIterator<K, T, T&, T*, KeyOfT, Hash> Iterator; typedef HTIterator<K, T, const T&, const T*, KeyOfT, Hash> ConstIterator; HashTable() :_tables(_stl_next_prime(0)) , _n(0) {} Iterator Begin() { if (_n == 0) return End(); for (size_t i = 0; i < _tables.size(); i++) { Node* cur = _tables[i]; if (cur) { return Iterator(cur, this); } } return End(); } Iterator End() { return Iterator(nullptr, this); } ConstIterator Begin() const { if (_n == 0) return End(); for (size_t i = 0; i < _tables.size(); i++) { Node* cur = _tables[i]; if (cur) { return ConstIterator(cur, this); } } return End(); } ConstIterator End() const { return ConstIterator(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; } } // 插入值为data的元素,如果data存在则不插入 pair<Iterator, bool> Insert(const T& data) { KeyOfT kot; Iterator it = Find(kot(data)); if (it != End()) return { it, false }; Hash hash; if (_n == _tables.size()) { vector<Node*> newtable(_stl_next_prime(_tables.size() + 1)); 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)) % newtable.size(); cur->_next = newtable[hashi]; newtable[hashi] = cur; cur = next; } } _tables.swap(newtable); } size_t hashi = hash(kot(data)) % _tables.size(); // 头插 Node* newnode = new Node(data); newnode->_next = _tables[hashi]; _tables[hashi] = newnode; ++_n; return { Iterator(newnode, this), false }; } // 在哈希桶中查找值为key的元素,存在返回true否则返回false? Iterator Find(const K& key) { KeyOfT kot; Hash hash; 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(); } // 哈希桶中删除key的元素,删除成功返回true,否则返回false bool Erase(const K& key) { KeyOfT kot; size_t hashi = key % _tables.size(); Node* prev = nullptr; Node* cur = _tables[hashi]; while (cur) { if (kot(cur->_data) == key) { if (prev == nullptr) { // 头结点 _tables[hashi] = cur->_next; } else { // 中间节点 prev->_next = cur->_next; } delete cur; --_n; return true; } else { prev = cur; cur = cur->_next; } } return false; } private: vector<Node*> _tables; // 指针数组 size_t _n = 0; // 表中存储数据个数 }; }