
目录
- #pragma once
- #include
- #include
- #include
//pair头文件 - #include
- #include
-
- using namespace std;
-
- namespace CLOSEHASH
- {
- enum State
- {
- EMPTY, //空
- EXIST, //存在
- DELETE //删除
- };
-
- template<class T>
- struct HashData
- {
- T _data;
- State _state; //代表数据状态
-
- HashData()
- :_state(EMPTY)
- ,_data(0)
- {}
- };
-
- template<class K, class T, class KeyOfT>
- class HashTable
- {
- typedef HashData
HashData; - public:
- bool Insert(const T& data)
- {
- KeyOfT koft;
- //1、增容:第一次插入或者负载因子>=0.7就要增容
- if (_tables.capacity() == 0 || _num * 10 / _tables.capacity() == 7)
- {
- //A、增容——传统思路
- //vector
newtables; - //size_t newcapacity = _tables.capacity() == 0 ? 10 : _tables.capacity() * 2;
- //newtables.resize(newcapacity);//开空间+自动初始化为0
- 把旧空间数据拷贝到新空间中
- //for (size_t i = 0; i < _tables.capacity(); ++i)
- //{
- // if (_tables[i]._state == EXIST)
- // {
- // size_t index = koft(_tables[i]._data) % newtables.capacity();
- // while (newtables[index]._state == EXIST)
- // {
- // index++;
-
- // if (index == newtables.capacity())
- // {
- // index = 0;//走到尾了就要返回头找位置
- // }
- // }
- // newtables[index] = _tables[i];
- // }
- //}
-
- //_tables.swap(newtables);
-
- //B、增容——简便思路
- HashTable
newht; - size_t newcapacity = _tables.capacity() == 0 ? 10 : _tables.capacity() * 2;
- newht._tables.resize(newcapacity);
-
- for (size_t i = 0; i < _tables.capacity(); ++i)
- {
- if (_tables[i]._state == EXIST)
- {
- newht.Insert(_tables[i]._data);//把原哈希表中每个数据利用Insert都插入到新哈希表中
- }
- }
-
- _tables.swap(newht._tables);//交换两者的vector
- }
-
- //1、线性探测
- //size_t index = koft(data) % _tables.capacity();//计算出要映射的位置
- //while (_tables[index]._state == EXIST)
- //{
- // if (koft(_tables[index]._data) == koft(data))
- // {
- // return false;//如果存在相同的数据
- // }
-
- // ++index;
- // if (index == _tables.capacity())
- // {
- // index = 0;
- // }
- //}
-
- //2、二次探测
- size_t start = koft(data) % _tables.capacity();
- size_t index = start;
- int i = 1;
- while (_tables[index]._state == EXIST)
- {
- if (koft(_tables[index]._data) == koft(data))
- {
- return false;
- }
-
- index = start + i * i;
- ++i;
- index %= _tables.capacity();
- }
-
- //插入数据
- _tables[index]._data = data;
- _tables[index]._state = EXIST;
- ++_num; //有效数据个数++
-
- return true;
- }
-
- HashData* Find(const K& key)
- {
- KeyOfT koft;
- size_t index = key % _tables.capacity();
- while(_tables[index]._state != EMPTY)
- {//只要是存在和删除状态就要持续往下找
- if (koft(_tables[index]._data) == key)
- {
- if (_tables[index]._state == EXIST)
- return &_tables[index];//值相等且为存在状态
- else
- return nullptr;//值相等但为删除状态,说明被删除了
- }
-
- ++index;//没找到继续往后找
- index %= _tables.capacity();
- }
-
- return nullptr;
- }
-
- bool Erase(const K& key)
- {
- HashData* ret = Find(key);
- if (ret)
- {
- ret->_state = DELETE;//用状态代表删除状态
- --_num; //--有效元素个数
- return true;
- }
- else
- {
- return false;
- }
- }
-
- private:
- vector
_tables; - size_t _num = 0; //表中存了多少个有效个数,不等于容量
- };
- }
-
- namespace OPENHASH
- {
- template<class T>
- struct HashNode
- {
- T _data;
- HashNode
* _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 __HashTableIterator
- {
- typedef __HashTableIterator
Self; - typedef HashTable
HT; - typedef HashNode
Node; - Node* _node;//迭代器中存的是节点指针
- HT* _pht;//对象的指针
-
- __HashTableIterator(Node* node, HT* pht)
- :_node(node)
- ,_pht(pht)
- {}
-
- T& operator*()
- {
- return _node->_data;
- }
-
- T* operator->()
- {
- return &_node->_data;
- }
-
- Self operator++()
- {
- if (_node->_next)
- {
- _node = _node->_next;
- }
- else
- {
- // 如果一个桶走完了,要往下找到下一个桶继续遍历
- KeyOfT koft;
- //先计算我当前是在哪个桶
- size_t i = _pht->HashFunc(koft(_node->_data)) % _pht->_tables.capacity();
- ++i;//下一个桶
- for (; i < _pht->_tables.capacity(); ++i)
- { //找不为空的桶
- Node* cur = _pht->_tables[i];
- if (cur)
- { //如果这个桶不为空
- _node = cur;
- return *this;
- }
- }
-
- _node = nullptr;//如果没有找到有数据的桶,则指针置为空,与end()相符
- return *this;
- }
- }
-
- bool operator!=(const Self& s)
- {
- return _node != s._node;
- }
- };
-
- template<class K>
- struct _Hash
- {
- const K& operator()(const K& key)
- {
- return key;//可以取模的直接返回即可
- }
- };
-
- //特化
- template<>
- struct _Hash
- {
- size_t operator()(const string& key)
- {
- //运用BKDR Hash算法
- size_t hash = 0;
- for (size_t i = 0; i < key.size(); ++i)
- {
- hash *= 131; //BKDR
- hash += key[i];//字符串中每个字母ASCII码值相加
- }
-
- return hash;
- }
- };
-
- template<class K, class T, class KeyOfT, class Hash>
- class HashTable
- {
- typedef HashNode
Node; - public:
- friend struct __HashTableIterator
;//因为迭代器要访问哈希表的私有成员_tables - typedef __HashTableIterator
iterator; -
- //begin()返回第一个不为空的桶的第一个节点
- iterator begin()
- {
- for (size_t i = 0; i < _tables.capacity(); ++i)
- {
- if (_tables[i])
- {
- return iterator(_tables[i], this);//找到了则构造匿名对象返回
- }
- }
-
- return end();//每个桶中都没找到则返回end()
- }
-
- iterator end()
- {
- return iterator(nullptr, this);
- }
-
- size_t HashFunc(const K& key)
- {
- Hash hash;
- return hash(key);//利用仿函数把key值转为整形
- }
-
- size_t GetNextPrime(size_t num)
- {
- const int PRIMECOUNT = 28;
- static const size_t primeList[PRIMECOUNT] =
- {
- 53ul, 97ul, 193ul, 389ul, 769ul,1543ul, 3079ul, 6151ul,
- 12289ul, 24593ul,49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
- 1572869ul, 3145739ul, 6291469ul, 12582917ul,25165843ul,50331653ul,
- 100663319ul, 201326611ul, 402653189ul,805306457ul,1610612741ul,
- 3221225473ul, 4294967291ul
- };
-
- for (size_t i = 0;; i < PRIMECOUNT; ++i)
- {
- if (primeList[i] > num)
- return primeList[i];
- }
-
- return primeList[PRIMECOUNT - 1];//如果num比我表中所有数据都大,默认返回表中最后一个
- }
-
- pair
bool > Insert(const T& data) - {
- KeyOfT koft;
- //1、判断是否增容
- if (_tables.capacity() == _num)
- { //开散列的实现平衡因子为1就增容且第一次插入也会增容
- //size_t newcapacity = _tables.capacity() == 0 ? 10 : _tables.capacity() * 2;
- size_t newcapacity = GetNextPrime(_tables.capacity());
- vector
newtables; - newtables.resize(newcapacity, nullptr);//给新的vector开新空间+初始化
- //重新计算旧表的数据在新表中的映射位置
- for (size_t i = 0; i < _tables.capacity(); ++i)
- { //如果是第一次的增容不会进for循环的,故不用担忧表的初始数据是否为nullptr
- //哈希表中每一个桶都是一个单链表,故考察单链表的头插
- Node* cur = _tables[i];
- while (cur)
- {
- Node* next = cur->_next;
- size_t index = HashFunc(koft(cur->_data)) % newtables.capacity();//重新计算映射位置
- //头插
- cur->_next = newtables[index];
- newtables[index] = cur;
-
- cur = next;
- }
- _tables[i] = nullptr;//映射到新表后置为空
- }
-
- _tables.swap(newtables);//新旧表的vector交换
-
- }
-
- size_t index = HashFunc(koft(data)) % _tables.capacity();//计算新的映射位置
-
- //1、先查找这个元素是否在哈希表中
- Node* cur = _tables[index];//知道映射位置就能确定是哪个桶
- while (cur)
- {
- if (koft(cur->_data) == koft(data))
- return make_pair(iterator(cur, this), false);//找到相同数据则插入失败
- else
- cur = cur->_next;
- }
-
- //2、头插到这个桶中
- Node* newnode = new Node(data);//开辟新节点
- //头插
- newnode->_next = _tables[index];
- _tables[index] = newnode;
-
- ++_num;//哈希表中有效元素个数++
- return make_pair(iterator(newnode, this), false);
- }
-
-
- Node* Find(const K& key)
- {
- KeyOfT koft;
- size_t index = HashFunc(key) % _tables.capacity();//先计算映射位置
- Node* cur = _tables[index];
- while (cur)
- {
- if (koft(cur->_data) == key)
- return cur;
- else
- cur = cur->_next;
- }
-
- return nullptr;//走遍桶都没找到则返回空
- }
-
- bool Erase(const K& key)
- {
- assert(_tables.capacity() > 0);//有空间才能删
-
- KeyOfT koft;
- size_t index = HashFunc(key) % _tables.capacity();
- Node* cur = _tables[index];
- Node* prev = nullptr;//记录cur的前一位置
-
- while (cur)
- {
- if (koft(cur->_data) == key)
- {
- if (prev == nullptr)
- { //如果是头删
- _tables[index] = cur->_next;
- }
- else
- {
- prev->_next = cur->_next;
- }
- delete cur;
- --_num;
-
- return true;
- }
- else
- {
- prev = cur;
- cur = cur->_next;
- }
- }
-
- return false;//要删除数据根本不存在
- }
-
- ~HashTable()
- {
- Clear();
- //vector不用我们释放,因为它是自定义类型,哈希表要清理时,vector也会自动清理
- }
-
- void Clear()
- {
- for (size_t i = 0; i < _tables.capacity(); ++i)
- {
- Node* cur = _tables[i];
- while (cur)
- {
- Node* next = cur->_next;
- delete cur;
- cur = next;
- }
-
- _tables[i] = nullptr;//清空完数据后置为nullptr
- }
- }
-
- private:
- vector
_tables; //使用vector一定要包含std库,不然使用不了 - size_t _num = 0; //有效元素的个数,不是容量
- };
-
- }
-
- #include"HashTable.h"
- #include"MyUnorderedMap.h"
- #include"MyUnorderedSet.h"
-
- template<class K>
- struct SetKeyOfT
- {
- const K& operator()(const K& key)
- {
- return key;
- }
- };
-
- void TestCloseHash()
- {
- CLOSEHASH::HashTable<int, int, SetKeyOfT<int>> ht;
- //CLOSEHASH::HashTable
> ht2; -
- ht.Insert(2);
- ht.Insert(4);
- ht.Insert(14);
- ht.Insert(24);
- ht.Insert(26);
- ht.Insert(16);
-
- ht.Erase(14);
- ht.Erase(2);
-
- CLOSEHASH::HashData<int>* data = ht.Find(4);
- }
-
- void TestOpenHash1()
- {
- using OPENHASH::_Hash;
-
- OPENHASH::HashTable<int, int, SetKeyOfT<int>, _Hash<int>> ht;
- //OPENHASH::HashTable
> ht2; -
- ht.Insert(2);
- ht.Insert(4);
- ht.Insert(14);
- ht.Insert(24);
- ht.Insert(26);
- ht.Insert(16);
-
- ht.Erase(14);
- ht.Erase(2);
-
- OPENHASH::HashNode<int>* Node = ht.Find(4);
-
- /*ht2.Insert(make_pair(1,1));
- ht2.Insert(4);
- ht2.Insert(14);
- ht2.Insert(24);
- ht2.Insert(26);
- ht2.Insert(16);
- ht2.Erase(14);
- ht2.Erase(2);
- HashNode
* Node2 = ht2.Find(4);*/ -
- }
-
- void TestOpenHash2()
- {
- using OPENHASH::_Hash;
-
- OPENHASH::HashTable
,_Hash> ht; - ht.Insert("sort");
- ht.Insert("futile");
- ht.Insert("plight");
-
- cout << ht.HashFunc("abcd") << endl;
- cout << ht.HashFunc("aadd") << endl;
-
- }
-
- int main()
- {
- //TestCloseHash();
- //TestOpenHash1();
- //TestOpenHash2();
- //mz::test_unordered_set();
- mz::test_unordered_map();
-
-
- return 0;
- }
- #pragma once
- #include"HashTable.h"
- using namespace OPENHASH;
-
- namespace mz
- {
- using OPENHASH::_Hash;
- template<class K, class Hash = _Hash
> - class unordered_set
- {
- struct SetKOfT
- {
- const K& operator()(const K& k)
- {
- return k;
- }
- };
-
- public:
- //加typename是告诉编译器这是个类型,你先让我过,等实例化了再去找
- //因为模板没实例化它是不接受你用模板里面的一个类型,故要用typename
-
- typedef typename HashTable
::iterator iterator; - iterator begin()
- {
- return _ht.begin();
- }
-
- iterator end()
- {
- return _ht.end();
- }
- pair
bool > insert(const K& k) - {
- return _ht.Insert(k);
- }
- private:
- HashTable
_ht; - };
-
- void test_unordered_set()
- {
- unordered_set<int> s;
- s.insert(1);
- s.insert(5);
- s.insert(4);
- s.insert(2);
-
- unordered_set<int>::iterator it = s.begin();
- while (it != s.end())
- {
- cout << *it << " ";
- ++it;
- }
- cout << endl;
- }
- }
MyUnorderedMap.h:
- #pragma once
- #include"HashTable.h"
- using namespace OPENHASH;
-
- namespace mz
- {
- using OPENHASH::_Hash;
- template<class K, class V, class Hash = _Hash
>//一般模板参数都是由上一层来控制的 - class unordered_map
- {
- struct MapKOfT
- {
- const K& operator()(const pair
& kv) - {
- return kv.first;
- }
- };
-
- public:
-
- typedef typename HashTable
, MapKOfT, Hash>::iterator iterator; - iterator begin()
- {
- return _ht.begin();
- }
-
- iterator end()
- {
- return _ht.end();
- }
-
- pair
bool > insert(const pair& kv) - {
- return _ht.Insert(kv);
- }
-
- V& operator[](const K& key)
- {
- pair
bool> ret = _ht.Insert(make_pair(key, V())); - return ret.first->second;
- }
-
- private:
- HashTable
, MapKOfT, Hash> _ht;//底层是个哈希表 - };
-
- void test_unordered_map()
- {
- unordered_map
dict; - dict.insert(make_pair("factual", "真实的"));
- dict.insert(make_pair("fringe", "侵犯"));
- dict.insert(make_pair("intermittent", "间歇的"));
- dict["prerequisite"] = "先决条件";
- dict["reduce to"] = "处于";
-
- //unordered_map
::iterator it = dict.begin(); - auto it = dict.begin();
- while (it != dict.end())
- {
- cout << it->first << ":" << it->second << endl;
- ++it;
- }
- cout << endl;
-
- }
- }