C++语法(22)---- 哈希表的闭散列和开散列_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/130436178?spm=1001.2014.3001.5501
1.重写HashTable
由于此时我们的实现与map跟set差不多,所以需要进行调整
1.重写节点
节点通过unordered_set和unordered_map传入的东西来构造是Value类型还是pair<K,V>类型
template<class T> struct HashNode { T _data; HashNode<T>* _next; HashNode(const T& data) :_data(data), _next(nullptr) {} };
2.重写哈希表
1.首先,一定要通过Key值查找对应的值,那么我们需要设置一个模板为K
2.我们还要传入哈希元素节点,设置模板为T(与上面一致)
3.将T的值进行哈希映射的Hash仿函数,该函数应该在unordered层传入,因为我们也不知道要映射到位置上的是什么
4.还有一个是与map和set实现一样的仿函数,用于区分到底是unordered_map还是unordered_set中的Key值的比较,该模板命名为KeyOfT
template<class K, class T, class Hash, class KeyOfT> class HashTable { typedef HashNode<T> Node; public: HashTable() :_n(0) { _table.resize(10); } ~HashTable() { //省略 } bool Insert(const T& data) { //需要注意获取哈希映射的方式 //需要用到hash转换k为对应的int再进行操作 KeyOfT kot; if (Find(kot(data)) != nullptr) return false; if (_n == _table.size()) { //省略怎么扩容的 } //需要注意获取哈希映射的方式 //需要用到上层传来的KeyOfT使得data变成可以被哈希映射的值 size_t hashi = kot(data) % _table.size(); //省略怎么插入的 } Node* Find(const K& k) { //需要注意获取哈希映射的方式 //需要用到hash转换k为对应的int再进行操作 size_t hashi = Hash()(k) % _table.size(); //省略怎么找的 } bool Erase(const K& k) { //需要注意获取哈希映射的方式 //需要用到hash转换k为对应的int再进行操作 size_t hashi = Hash()(k) % _table.size(); //省略怎么删除的 } private: vector<Node*> _table; size_t _n = 0; };
2.unordered初步实现
1.unordered_set
对于set而言,传入的直接就是Key,那么SetOfT仿函数返回的就是key
namespace MY { template<class K,class Hash = HashFunc<K>> class unordered_set { struct SetOfT { const K& operator()(const K& key) { return key; } }; private: buckethash::HashTable<K, K, Hash, SetOfT> _ht; }; }
2.unordered_map
对于map而言,传入的是pair,那么MapOfT仿函数返回的就是pair的first
namespace MY { template<class K, class V, class Hash = HashFunc<K>> class unordered_map { struct MapOfT { const K& operator()(const pair<const K, V>& key) { return key.first; } }; private: buckethash::HashTable<K, pair<const K, V>, Hash, MapOfT> _ht; }; }
3. 哈希表的迭代器
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; };
我们需要算到开始的位置,所以一定要传入哈希表的地址,随后访问到哈希表的tables。
迭代器的简单函数
__HTIterator(Node* node,HT* ht) :_node(node) ,_ht(ht) {} T operator*() { return _node->_data; } T& operator->() { return &_node->_data; } bool operator != (const Self& s) const { return _node != s._node; }
重写++的实现
首先我们找到下一个位置有两种情况
1.指针往下就是下一个数
2.整个桶走完了,我们要找下一个桶有数据的位置
Self& operator++() { if (_node->_next) { _node = _node->_next; } else { KeyOfT kot; Hash hash; size_t hashi = hash(kot(_node->_data)) % (_ht->_table.size()); hashi++; while (hashi < _ht->_table.size()) { if (_ht->_table[hashi]) { _node = _ht->_table[hashi]; break; } else ++hashi; } if (hashi == _ht->_table.size()) { _node = nullptr; } } return *this; }
因为迭代器用到了哈希表,但是我将迭代器写在了哈希表的前面,所以在此之前还得先定义哈希表的前置声明
//前置声明 template<class K, class T, class Hash, class KeyOfT> class HashTable;
4.哈希表的迭代器形式
1.迭代器怎么才使用_table
由于哈希表中的table是私有对象,而迭代器需要访问table,那么就要将迭代器设置为哈希表的友元。
template<class K, class T, class Hash, class KeyOfT> class HashTable { typedef HashNode<T> Node; template<class K, class T, class Hash, class KeyOfT> friend struct __HTIterator; //友元 public: typedef __HTIterator<K, T, Hash, KeyOfT> iterator; private: vector<Node*> _table; size_t _n = 0; };
2.哈希表中的迭代器
需要注意的是,在迭代器中,构造函数为:
__HTIterator(Node* node,HT* ht) :_node(node) ,_ht(ht) {}
所以哈希表的函数返回包括迭代器内容的,一律需要构造迭代器返回。
_node:就是生成的节点的地址,该地址就是节点的指针,这个好获得
_ht:为哈希表的地址,那么我们在哈希表的类中,本身的对象就是_ht,我们只需要返回this
iterator begin() { for (size_t i = 0; i < _table.size(); i++) { if (_table[i] != nullptr) return iterator(_table[i], this); } return iterator(nullptr, this); } iterator end() { return iterator(nullptr, this); }
iterator Find(const K& k) { size_t hashi = Hash()(k) % _table.size(); Node* cur = _table[hashi]; KeyOfT kot; while (cur) { if (kot(cur->_data) == k) return iterator(cur, this); else cur = cur->_next; } return iterator(nullptr,this); } bool Erase(const K& k) { size_t hashi = Hash()(k) % _table.size(); Node* cur = _table[hashi]; Node* prev = nullptr; while (cur) { if (cur->_kv.first == k) { if (cur == _table[hashi]) _table[hashi] = cur->_next; else prev->_next = cur->_next; delete cur; _n--; return true; } prev = cur; cur = cur->_next; } return false; }
因为需要实现map的operator[],因此insert的重写是返回一个pair类型,first是迭代器,second是bool。
pair<iterator, bool> Insert(const T& data) { KeyOfT kot; iterator it = Find(kot(data)); if (it != end()) return make_pair(it, false); if (_n == _table.size()) { vector<Node*> newTable; newTable.resize(2 * _table.size(),nullptr); for (int i = 0; i < _table.size(); i++) { Node* cur = _table[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; } _table[i] = nullptr; } _table.swap(newTable); } size_t hashi = Hash()(kot(data)) % _table.size(); Node* newnode = new Node(data); newnode->_next = _table[hashi]; _table[hashi] = newnode; _n++; return make_pair(iterator(newnode, this), true); }
5.unordered_map和unordered_set
template<class K, class V, class Hash = HashFunc<K>> class unordered_map { struct MapOfT { const K& operator()(const pair<const K, V>& key) { return key.first; } }; public: typedef typename buckethash::HashTable<K, pair<const K, V>, Hash, MapOfT>::iterator iterator; iterator begin() { return _ht.begin(); } iterator end() { return _ht.end(); } iterator Find(const K& k) { return _ht.Find(k); } bool Erase(const K& k) { return _ht.Erase(k); } pair<iterator, bool> insert(const pair<const K, V>& data) { return _ht.Insert(data); } V& operator[](const K& key) { pair<iterator, bool> ret = _ht.Insert(make_pair(key, V())); return ret.first->second; } private: buckethash::HashTable<K, pair<const K, V>, Hash, MapOfT> _ht; };
template<class K,class Hash = HashFunc<K>> class unordered_set { struct SetOfT { const K& operator()(const K& key) { return key; } }; public: typedef typename buckethash::HashTable<K, K, Hash, SetOfT>::iterator iterator; iterator begin() { return _ht.begin(); } iterator end() { return _ht.end(); } iterator Find(const K& k) { return _ht.Find(k); } bool Erase(const K& k) { return _ht.Erase(k); } pair<iterator, bool> insert(const K& key) { return _ht.Insert(key); } private: buckethash::HashTable<K, K, Hash, SetOfT> _ht; };