目录
1.哈希表(开散列)实现
1.1 介绍模板参数
1.2 代码实现
2.迭代器
3.HASH转整形的类
4.unordered_map简单实现
5.unordered_map简单实现
6.验证
1.哈希表(开散列)实现
1.1 介绍模板参数
//K:关键码
//T:保存数据,unordered_map是一个键值对,unordered_set是K
//KeyOfT:由于unordered_map和unordered_set保存值不同,KOFT是一个仿函数,取出关键码。。
//HashFunc:仿函数,将关键码Key不是整形类型转成整形。
//模板参数是由unordered_set和unordered_map传入的
template<class K, class T, class KeyOfT, class HashFunc>
class HashTable;
1.2 代码实现
namespace CH3
{//为了确保“K”可以取余template<class K>struct DefaultHashFunc{size_t operator()(const K& key){return (size_t)key;}};template<>struct DefaultHashFunc<string>{size_t operator()(const string& str){int sum = 0;for (auto& x : str){sum *= 131;sum += x;}return sum;}};//用“T”是因为不知道,传过来的是set还是maptemplate<class T>struct HashNode{T _date;//存数据HashNode<T>* _next;//保存下一个节点HashNode(const T& date):_date(date), _next(nullptr){}};// 前置声明template<class K, class T, class KeyOfT, class HashFunc>//因为在Iterator中使用了HashTable//所以需要提前声明,否则找不到class HashTable;template<class K, class T, class KeyOfT, class HashFunc>struct Iterator{typedef HashNode<T> Node;typedef Iterator<K, T, KeyOfT, HashFunc> Self;Node* _node;//保存节点是为了找到下一个节点HashTable<K, T, KeyOfT, HashFunc>* _pve;//保存哈希表的指针,当这一列找完了,可以找到下一列Iterator(Node* node, HashTable<K, T, KeyOfT, HashFunc>* pve):_node(node),_pve(pve){}T& operator*(){return _node->_date;}T* operator->(){return &_node->_date;}Self& operator++(){KeyOfT kt;HashFunc ht;//返回下一迭代器if (_node->_next){_node = _node->_next;}else{size_t hashi = ht(kt(_node->_date)) % _pve->_table.size();//找当前节点在哈希表的下标hashi++;while (hashi < _pve->_table.size()){if (_pve->_table[hashi]){_node = _pve->_table[hashi];return *this;}else{hashi++;}}_node = nullptr;return *this;}return *this;}bool operator!=(const Self& pve){return _node != pve._node;}};template<class K, class T,class KeyOfT,class HashFunc = DefaultHashFunc<K>>class HashTable{typedef HashNode<T> Node;// 友元声明template<class K, class T, class KeyOfT, class HashFunc>friend struct Iterator;public:typedef Iterator<K, T, KeyOfT, HashFunc> iterator;iterator begin(){for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];if (cur){return iterator(cur, this);}}return iterator(nullptr, this);}iterator end(){return iterator(nullptr, this);}HashTable(){_table.resize(10, nullptr);}~HashTable(){for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;delete cur;cur = next;}_table[i] = nullptr;}}bool insert(const T& kv){HashFunc ht;KeyOfT kt;//扩容if (_n == _table.size()){size_t newhashi = 2 * _table.size();vector<Node*> newtable;newtable.resize(newhashi, nullptr);//将旧表的每一列的节点移至新表中for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;size_t hashi = ht(kt(cur->_date)) % newtable.size();cur->_next = newtable[hashi];newtable[hashi] = cur;cur = next;}_table[i] = nullptr;}//新旧表之间的交换_table.swap(newtable);}//找到该节点,插入哈希表的第几列size_t hashi = ht(kt(kv)) % _table.size();Node* cur = new Node(kv);cur->_next = _table[hashi];_table[hashi] = cur;_n++;return true;}Node* Find(const K& key){HashFunc ht;KeyOfT kt;size_t hashi = ht(key) % _table.size();//找到该节点所在的列Node* cur = _table[hashi];//在这一列找是否存在while (cur){Node* next = cur->_next;if (ht(kt(cur->_date)) == key){return cur;}cur = next;}return nullptr;}//删除bool erase(const K& key){HashFunc ht;KeyOfT kt;size_t hashi = ht(key) % _table.size();Node* cur = _table[hashi];Node* prve = nullptr;while (cur){if (ht(kt(cur->_date)) == key){//头删//中间删if (prve == nullptr){_table[hashi] = cur->_next;}else{prve->_next = cur->_next;}delete cur;return true;}prve = cur;cur = cur->_next;}_n--;return false;}void print(){KeyOfT kt;for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];printf("%d->", i);while (cur){cout << kt(cur->_date) << "->";cur = cur->_next;}cout << "Null" << endl;}cout << endl;}private:vector<Node*> _table;size_t _n = 0;};
}
2.迭代器
这里实现的迭代器的++,是在哈希桶中找到第一个桶的,遍历完桶的结点,再找下一个桶遍历。
由于当遍历完当前桶要找下一个桶的位置。迭代器中还需要添加一个哈希桶指针,指向当前哈希桶。
实现operator++操作:
1.如果当前结点下一个结点不为空,走向下一个结点。
2..如果当前结点的下一个结点为空,找到当前结点在哈希桶中的位置(利当前结点的值和哈希函数求出)。再在哈希桶里找下一个桶。这里会访问到哈希桶的成员变量(私有),需要将迭代器设为哈希桶的友元类。
// 前置声明template<class K, class T, class KeyOfT, class HashFunc>//因为在Iterator中使用了HashTable//所以需要提前声明,否则找不到class HashTable;//迭代器template<class K, class T, class KeyOfT, class HashFunc>//由于使用了哈希表指针,使用也要加上模板参数struct Iterator{typedef HashNode<T> Node;typedef Iterator<K, T, KeyOfT, HashFunc> Self;Node* _node;//保存节点是为了找到下一个节点HashTable<K, T, KeyOfT, HashFunc>* _pve;//保存哈希表的指针,当这一列找完了,可以找到下一列Iterator(Node* node, HashTable<K, T, KeyOfT, HashFunc>* pve):_node(node),_pve(pve){}T& operator*(){return _node->_date;}T* operator->(){return &_node->_date;}Self& operator++(){KeyOfT kt;HashFunc ht;if (_node->_next){_node = _node->_next;}else{size_t hashi = ht(kt(_node->_date)) % _pve->_table.size();//找当前节点在哈希表的下标hashi++;while (hashi < _pve->_table.size()){if (_pve->_table[hashi]){_node = _pve->_table[hashi];return *this;}else{hashi++;}}_node = nullptr;return *this;}return *this;}bool operator!=(const Self& pve){return _node != pve._node;}};
3.HASH转整形的类
//装整形的类,默认整形,直接返回template<class K>struct DefaultHashFunc{size_t operator()(const K& key){return (size_t)key;}};//装整形的类,默认整形,直接返回template<>struct DefaultHashFunc<string>{size_t operator()(const string& str){int sum = 0;for (auto& x : str){sum *= 131;sum += x;}return sum;}};
如果不是这两种,则需要在用户自己编写,传入模板参数。
4.unordered_map简单实现
这里只是简单实现了迭代器
如想实现查找,删除,可直接调用哈希用的查找和删除,只需要改变返回值类型。
namespace CH
{template<class K,class V>class unordered_map{//仿函数(),用于返回 "K" 的值,写这个是为了取出map的“K”struct MapKeyOfT{const K& operator()(const pair<K,V>& kv){return kv.first;}};public://取一个类中的类,要加typenametypedef typename CH3::HashTable<K,pair<K,V>, MapKeyOfT>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}bool insert(const pair<K,V>& kv){return _ht.insert(kv);}void print(){_ht.print();}private:CH3::HashTable<K, pair<K,V>, MapKeyOfT> _ht;};
}
5.unordered_map简单实现
namespace CH
{template<class K>class unordered_set{//仿函数struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename CH3::HashTable<K, K, SetKeyOfT>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}bool insert(const K& key){return _ht.insert(key);}void print(){_ht.print();}private:CH3::HashTable<K, K, SetKeyOfT> _ht;};
}