基于开散列封装哈希表:
HashTable.h
#pragma once
#include<vector>template<class K>
struct HashFunc
{size_t operator()(const K& key){return (size_t)key;}
};// 特化
template<>
struct HashFunc<string>
{// abcd// bcad// aadd// BKDRsize_t operator()(const string& key){size_t hash = 0;for (auto ch : key){hash *= 131;hash += ch;}return hash;}
};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 KeyOfT, class Hash>//struct __HTIterator//{// typedef HashNode<T> Node;// typedef __HTIterator<K, T, KeyOfT, Hash> Self;// Node* _node;// HashTable<K, T, KeyOfT, Hash>* _pht;// __HTIterator(Node* node, HashTable<K, T, KeyOfT, Hash>* pht)// :_node(node)// ,_pht(pht)// {}// T& operator*()// {// return _node->_data;// }// Self& operator++()// {// if (_node->_next)// {// // 当前桶没走完,找当前桶的下一个节点// _node = _node->_next;// }// else// {// // 当前桶走完了,找下一个不为空的桶的第一个节点// KeyOfT kot;// Hash hs;// size_t i = hs(kot(_node->_data)) % _pht->_tables.size();// ++i;// for (; i < _pht->_tables.size(); i++)// {// if (_pht->_tables[i])// break;// }// if (i == _pht->_tables.size())// {// // 所有桶都走完了,最后一个的下一个用nullptr标记// _node = nullptr;// }// else// {// _node = _pht->_tables[i];// }// }// return *this;// }// bool operator!=(const Self& s)// {// return _node != s._node;// }//};template<class K, class T, class KeyOfT, class Hash>class HashTable{typedef HashNode<T> Node;public:// 友元声明/*template<class K, class T, class KeyOfT, class Hash>friend struct __HTIterator;*/// 内部类template<class Ptr, class Ref>struct __HTIterator{typedef HashNode<T> Node;typedef __HTIterator Self;Node* _node;const HashTable* _pht;__HTIterator(Node* node, const HashTable* pht):_node(node), _pht(pht){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}Self& operator++(){if (_node->_next){// 当前桶没走完,找当前桶的下一个节点_node = _node->_next;}else{// 当前桶走完了,找下一个不为空的桶的第一个节点KeyOfT kot;Hash hs;size_t i = hs(kot(_node->_data)) % _pht->_tables.size();++i;for (; i < _pht->_tables.size(); i++){if (_pht->_tables[i])break;}if (i == _pht->_tables.size()){// 所有桶都走完了,最后一个的下一个用nullptr标记_node = nullptr;}else{_node = _pht->_tables[i];}}return *this;}bool operator!=(const Self& s){return _node != s._node;}};typedef __HTIterator<T*, T&> iterator;typedef __HTIterator<const T*, const T&> const_iterator;iterator begin(){for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];if (cur){// this -> HashTable*return iterator(cur, this);}}return end();}iterator end(){return iterator(nullptr, this);}const_iterator begin() const{for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];if (cur){// this -> const HashTable*return const_iterator(cur, this);}}return end();}const_iterator end() const{return const_iterator(nullptr, this);}HashTable(){_tables.resize(10, nullptr);_n = 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;}}pair<iterator, bool> Insert(const T& data){KeyOfT kot;iterator it = Find(kot(data));if (it != end())return make_pair(it, false);Hash hs;// 扩容// 负载因子为1时扩容if (_n == _tables.size()){//HashTable<K, V> newHT;//newHT._tables.resize(_tables.size() * 2);旧表重新计算负载到新表//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(_tables.size() * 2, nullptr);for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;// 头插新表的位置size_t hashi = hs(kot(cur->_data)) % newTables.size();cur->_next = newTables[hashi];newTables[hashi] = cur;cur = next;}_tables[i] = nullptr;}_tables.swap(newTables);}size_t hashi = hs(kot(data)) % _tables.size();Node* newnode = new Node(data);// 头插newnode->_next = _tables[hashi];_tables[hashi] = newnode;++_n;return make_pair(iterator(newnode, this), true);}iterator Find(const K& key){KeyOfT kot;Hash hs;size_t hashi = hs(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){KeyOfT kot;Hash hs;size_t hashi = hs(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;return true;}else{prev = cur;cur = cur->_next;}}return false;}private:vector<Node*> _tables; // 指针数组size_t _n;//vector<list<pair<K, V>>> _tables;};//void TestHT1()//{// int a[] = { 10001,11,55,24,19,12,31,4,34,44};// HashTable<int, int> ht;// for (auto e : a)// {// ht.Insert(make_pair(e, e));// }// ht.Insert(make_pair(32, 32));// ht.Insert(make_pair(32, 32));// ht.Erase(31);// ht.Erase(11);//}//void TestHT2()//{// HashTable<string, int> ht;// ht.Insert(make_pair("sort", 1));// ht.Insert(make_pair("left", 1));// ht.Insert(make_pair("insert", 1));//}
}
基于哈希表实现unordered_set类
基于HashTable.h封装的哈希表类提供的接口,实现一个unordered_set类。
my_unordered_set.h
该文件基本实现了unordered_set类。
#pragma once#include"HashTable.h"namespace xx
{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>::const_iterator 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 Func(const unordered_set<int>& s){unordered_set<int>::iterator it = s.begin();while (it != s.end()){//*it = 1;cout << *it << " ";++it;}cout << endl;}void test_unordered_set(){unordered_set<int> s;s.insert(31);s.insert(11);s.insert(5);s.insert(15);s.insert(25);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;}
}
基于哈希表实现unordered_map类
基于my_unordered_map.h封装的哈希表类提供的接口,实现一个unordered_map。unordered_map的值是一个键值对。
Myunordered_map.h
该文件基本实现了unordered_map类。
#pragma oncenamespace xx
{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;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}V& operator[](const K& key){pair<iterator, bool> ret = insert(make_pair(key, V()));return ret.first->second;}pair<iterator, bool> insert(const pair<K, V>& kv){return _ht.Insert(kv);}private:hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;};void test_unordered_map(){string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉","苹果","草莓", "苹果","草莓" };unordered_map<string, int> countMap;for (auto& e : arr){countMap[e]++;}unordered_map<string, int>::iterator it = countMap.begin();while (it != countMap.end()){//it->first += 'x'; // key不能修改it->second += 1; // value可以修改cout << it->first << ":" << it->second << endl;++it;}cout << endl;for (auto& kv : countMap){cout << kv.first << ":" << kv.second << endl;}cout << endl;}
}
源文件test.cpp:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;#include"HashTable.h"
#include"my_unordered_set.h"
#include"my_unordered_map.h"int main()
{xx::test_unordered_map();return 0;
}