• 【哈希表完整代码】模拟实现哈希表和unordered_set与unordered_map


    目录

    HashTable.h:

    Test.cpp:

    MyUnorderedSet.h:


    HashTable.h:

    1. #pragma once
    2. #include
    3. #include
    4. #include//pair头文件
    5. #include
    6. #include
    7. using namespace std;
    8. namespace CLOSEHASH
    9. {
    10. enum State
    11. {
    12. EMPTY, //空
    13. EXIST, //存在
    14. DELETE //删除
    15. };
    16. template<class T>
    17. struct HashData
    18. {
    19. T _data;
    20. State _state; //代表数据状态
    21. HashData()
    22. :_state(EMPTY)
    23. ,_data(0)
    24. {}
    25. };
    26. template<class K, class T, class KeyOfT>
    27. class HashTable
    28. {
    29. typedef HashData HashData;
    30. public:
    31. bool Insert(const T& data)
    32. {
    33. KeyOfT koft;
    34. //1、增容:第一次插入或者负载因子>=0.7就要增容
    35. if (_tables.capacity() == 0 || _num * 10 / _tables.capacity() == 7)
    36. {
    37. //A、增容——传统思路
    38. //vector newtables;
    39. //size_t newcapacity = _tables.capacity() == 0 ? 10 : _tables.capacity() * 2;
    40. //newtables.resize(newcapacity);//开空间+自动初始化为0
    41. 把旧空间数据拷贝到新空间中
    42. //for (size_t i = 0; i < _tables.capacity(); ++i)
    43. //{
    44. // if (_tables[i]._state == EXIST)
    45. // {
    46. // size_t index = koft(_tables[i]._data) % newtables.capacity();
    47. // while (newtables[index]._state == EXIST)
    48. // {
    49. // index++;
    50. // if (index == newtables.capacity())
    51. // {
    52. // index = 0;//走到尾了就要返回头找位置
    53. // }
    54. // }
    55. // newtables[index] = _tables[i];
    56. // }
    57. //}
    58. //_tables.swap(newtables);
    59. //B、增容——简便思路
    60. HashTable newht;
    61. size_t newcapacity = _tables.capacity() == 0 ? 10 : _tables.capacity() * 2;
    62. newht._tables.resize(newcapacity);
    63. for (size_t i = 0; i < _tables.capacity(); ++i)
    64. {
    65. if (_tables[i]._state == EXIST)
    66. {
    67. newht.Insert(_tables[i]._data);//把原哈希表中每个数据利用Insert都插入到新哈希表中
    68. }
    69. }
    70. _tables.swap(newht._tables);//交换两者的vector
    71. }
    72. //1、线性探测
    73. //size_t index = koft(data) % _tables.capacity();//计算出要映射的位置
    74. //while (_tables[index]._state == EXIST)
    75. //{
    76. // if (koft(_tables[index]._data) == koft(data))
    77. // {
    78. // return false;//如果存在相同的数据
    79. // }
    80. // ++index;
    81. // if (index == _tables.capacity())
    82. // {
    83. // index = 0;
    84. // }
    85. //}
    86. //2、二次探测
    87. size_t start = koft(data) % _tables.capacity();
    88. size_t index = start;
    89. int i = 1;
    90. while (_tables[index]._state == EXIST)
    91. {
    92. if (koft(_tables[index]._data) == koft(data))
    93. {
    94. return false;
    95. }
    96. index = start + i * i;
    97. ++i;
    98. index %= _tables.capacity();
    99. }
    100. //插入数据
    101. _tables[index]._data = data;
    102. _tables[index]._state = EXIST;
    103. ++_num; //有效数据个数++
    104. return true;
    105. }
    106. HashData* Find(const K& key)
    107. {
    108. KeyOfT koft;
    109. size_t index = key % _tables.capacity();
    110. while(_tables[index]._state != EMPTY)
    111. {//只要是存在和删除状态就要持续往下找
    112. if (koft(_tables[index]._data) == key)
    113. {
    114. if (_tables[index]._state == EXIST)
    115. return &_tables[index];//值相等且为存在状态
    116. else
    117. return nullptr;//值相等但为删除状态,说明被删除了
    118. }
    119. ++index;//没找到继续往后找
    120. index %= _tables.capacity();
    121. }
    122. return nullptr;
    123. }
    124. bool Erase(const K& key)
    125. {
    126. HashData* ret = Find(key);
    127. if (ret)
    128. {
    129. ret->_state = DELETE;//用状态代表删除状态
    130. --_num; //--有效元素个数
    131. return true;
    132. }
    133. else
    134. {
    135. return false;
    136. }
    137. }
    138. private:
    139. vector _tables;
    140. size_t _num = 0; //表中存了多少个有效个数,不等于容量
    141. };
    142. }
    143. namespace OPENHASH
    144. {
    145. template<class T>
    146. struct HashNode
    147. {
    148. T _data;
    149. HashNode* _next;
    150. HashNode(const T& data)
    151. :_data(data)
    152. , _next(nullptr)
    153. {}
    154. };
    155. //前置声明:为了让哈希表的迭代器能用哈希表
    156. template<class K, class T, class KeyOfT, class Hash>
    157. class HashTable;
    158. template<class K, class T, class KeyOfT, class Hash>
    159. struct __HashTableIterator
    160. {
    161. typedef __HashTableIterator Self;
    162. typedef HashTable HT;
    163. typedef HashNode Node;
    164. Node* _node;//迭代器中存的是节点指针
    165. HT* _pht;//对象的指针
    166. __HashTableIterator(Node* node, HT* pht)
    167. :_node(node)
    168. ,_pht(pht)
    169. {}
    170. T& operator*()
    171. {
    172. return _node->_data;
    173. }
    174. T* operator->()
    175. {
    176. return &_node->_data;
    177. }
    178. Self operator++()
    179. {
    180. if (_node->_next)
    181. {
    182. _node = _node->_next;
    183. }
    184. else
    185. {
    186. // 如果一个桶走完了,要往下找到下一个桶继续遍历
    187. KeyOfT koft;
    188. //先计算我当前是在哪个桶
    189. size_t i = _pht->HashFunc(koft(_node->_data)) % _pht->_tables.capacity();
    190. ++i;//下一个桶
    191. for (; i < _pht->_tables.capacity(); ++i)
    192. { //找不为空的桶
    193. Node* cur = _pht->_tables[i];
    194. if (cur)
    195. { //如果这个桶不为空
    196. _node = cur;
    197. return *this;
    198. }
    199. }
    200. _node = nullptr;//如果没有找到有数据的桶,则指针置为空,与end()相符
    201. return *this;
    202. }
    203. }
    204. bool operator!=(const Self& s)
    205. {
    206. return _node != s._node;
    207. }
    208. };
    209. template<class K>
    210. struct _Hash
    211. {
    212. const K& operator()(const K& key)
    213. {
    214. return key;//可以取模的直接返回即可
    215. }
    216. };
    217. //特化
    218. template<>
    219. struct _Hash
    220. {
    221. size_t operator()(const string& key)
    222. {
    223. //运用BKDR Hash算法
    224. size_t hash = 0;
    225. for (size_t i = 0; i < key.size(); ++i)
    226. {
    227. hash *= 131; //BKDR
    228. hash += key[i];//字符串中每个字母ASCII码值相加
    229. }
    230. return hash;
    231. }
    232. };
    233. template<class K, class T, class KeyOfT, class Hash>
    234. class HashTable
    235. {
    236. typedef HashNode Node;
    237. public:
    238. friend struct __HashTableIterator;//因为迭代器要访问哈希表的私有成员_tables
    239. typedef __HashTableIterator iterator;
    240. //begin()返回第一个不为空的桶的第一个节点
    241. iterator begin()
    242. {
    243. for (size_t i = 0; i < _tables.capacity(); ++i)
    244. {
    245. if (_tables[i])
    246. {
    247. return iterator(_tables[i], this);//找到了则构造匿名对象返回
    248. }
    249. }
    250. return end();//每个桶中都没找到则返回end()
    251. }
    252. iterator end()
    253. {
    254. return iterator(nullptr, this);
    255. }
    256. size_t HashFunc(const K& key)
    257. {
    258. Hash hash;
    259. return hash(key);//利用仿函数把key值转为整形
    260. }
    261. size_t GetNextPrime(size_t num)
    262. {
    263. const int PRIMECOUNT = 28;
    264. static const size_t primeList[PRIMECOUNT] =
    265. {
    266. 53ul, 97ul, 193ul, 389ul, 769ul,1543ul, 3079ul, 6151ul,
    267. 12289ul, 24593ul,49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
    268. 1572869ul, 3145739ul, 6291469ul, 12582917ul,25165843ul,50331653ul,
    269. 100663319ul, 201326611ul, 402653189ul,805306457ul,1610612741ul,
    270. 3221225473ul, 4294967291ul
    271. };
    272. for (size_t i = 0;; i < PRIMECOUNT; ++i)
    273. {
    274. if (primeList[i] > num)
    275. return primeList[i];
    276. }
    277. return primeList[PRIMECOUNT - 1];//如果num比我表中所有数据都大,默认返回表中最后一个
    278. }
    279. pairbool> Insert(const T& data)
    280. {
    281. KeyOfT koft;
    282. //1、判断是否增容
    283. if (_tables.capacity() == _num)
    284. { //开散列的实现平衡因子为1就增容且第一次插入也会增容
    285. //size_t newcapacity = _tables.capacity() == 0 ? 10 : _tables.capacity() * 2;
    286. size_t newcapacity = GetNextPrime(_tables.capacity());
    287. vector newtables;
    288. newtables.resize(newcapacity, nullptr);//给新的vector开新空间+初始化
    289. //重新计算旧表的数据在新表中的映射位置
    290. for (size_t i = 0; i < _tables.capacity(); ++i)
    291. { //如果是第一次的增容不会进for循环的,故不用担忧表的初始数据是否为nullptr
    292. //哈希表中每一个桶都是一个单链表,故考察单链表的头插
    293. Node* cur = _tables[i];
    294. while (cur)
    295. {
    296. Node* next = cur->_next;
    297. size_t index = HashFunc(koft(cur->_data)) % newtables.capacity();//重新计算映射位置
    298. //头插
    299. cur->_next = newtables[index];
    300. newtables[index] = cur;
    301. cur = next;
    302. }
    303. _tables[i] = nullptr;//映射到新表后置为空
    304. }
    305. _tables.swap(newtables);//新旧表的vector交换
    306. }
    307. size_t index = HashFunc(koft(data)) % _tables.capacity();//计算新的映射位置
    308. //1、先查找这个元素是否在哈希表中
    309. Node* cur = _tables[index];//知道映射位置就能确定是哪个桶
    310. while (cur)
    311. {
    312. if (koft(cur->_data) == koft(data))
    313. return make_pair(iterator(cur, this), false);//找到相同数据则插入失败
    314. else
    315. cur = cur->_next;
    316. }
    317. //2、头插到这个桶中
    318. Node* newnode = new Node(data);//开辟新节点
    319. //头插
    320. newnode->_next = _tables[index];
    321. _tables[index] = newnode;
    322. ++_num;//哈希表中有效元素个数++
    323. return make_pair(iterator(newnode, this), false);
    324. }
    325. Node* Find(const K& key)
    326. {
    327. KeyOfT koft;
    328. size_t index = HashFunc(key) % _tables.capacity();//先计算映射位置
    329. Node* cur = _tables[index];
    330. while (cur)
    331. {
    332. if (koft(cur->_data) == key)
    333. return cur;
    334. else
    335. cur = cur->_next;
    336. }
    337. return nullptr;//走遍桶都没找到则返回空
    338. }
    339. bool Erase(const K& key)
    340. {
    341. assert(_tables.capacity() > 0);//有空间才能删
    342. KeyOfT koft;
    343. size_t index = HashFunc(key) % _tables.capacity();
    344. Node* cur = _tables[index];
    345. Node* prev = nullptr;//记录cur的前一位置
    346. while (cur)
    347. {
    348. if (koft(cur->_data) == key)
    349. {
    350. if (prev == nullptr)
    351. { //如果是头删
    352. _tables[index] = cur->_next;
    353. }
    354. else
    355. {
    356. prev->_next = cur->_next;
    357. }
    358. delete cur;
    359. --_num;
    360. return true;
    361. }
    362. else
    363. {
    364. prev = cur;
    365. cur = cur->_next;
    366. }
    367. }
    368. return false;//要删除数据根本不存在
    369. }
    370. ~HashTable()
    371. {
    372. Clear();
    373. //vector不用我们释放,因为它是自定义类型,哈希表要清理时,vector也会自动清理
    374. }
    375. void Clear()
    376. {
    377. for (size_t i = 0; i < _tables.capacity(); ++i)
    378. {
    379. Node* cur = _tables[i];
    380. while (cur)
    381. {
    382. Node* next = cur->_next;
    383. delete cur;
    384. cur = next;
    385. }
    386. _tables[i] = nullptr;//清空完数据后置为nullptr
    387. }
    388. }
    389. private:
    390. vector _tables; //使用vector一定要包含std库,不然使用不了
    391. size_t _num = 0; //有效元素的个数,不是容量
    392. };
    393. }

    Test.cpp:

    1. #include"HashTable.h"
    2. #include"MyUnorderedMap.h"
    3. #include"MyUnorderedSet.h"
    4. template<class K>
    5. struct SetKeyOfT
    6. {
    7. const K& operator()(const K& key)
    8. {
    9. return key;
    10. }
    11. };
    12. void TestCloseHash()
    13. {
    14. CLOSEHASH::HashTable<int, int, SetKeyOfT<int>> ht;
    15. //CLOSEHASH::HashTable> ht2;
    16. ht.Insert(2);
    17. ht.Insert(4);
    18. ht.Insert(14);
    19. ht.Insert(24);
    20. ht.Insert(26);
    21. ht.Insert(16);
    22. ht.Erase(14);
    23. ht.Erase(2);
    24. CLOSEHASH::HashData<int>* data = ht.Find(4);
    25. }
    26. void TestOpenHash1()
    27. {
    28. using OPENHASH::_Hash;
    29. OPENHASH::HashTable<int, int, SetKeyOfT<int>, _Hash<int>> ht;
    30. //OPENHASH::HashTable> ht2;
    31. ht.Insert(2);
    32. ht.Insert(4);
    33. ht.Insert(14);
    34. ht.Insert(24);
    35. ht.Insert(26);
    36. ht.Insert(16);
    37. ht.Erase(14);
    38. ht.Erase(2);
    39. OPENHASH::HashNode<int>* Node = ht.Find(4);
    40. /*ht2.Insert(make_pair(1,1));
    41. ht2.Insert(4);
    42. ht2.Insert(14);
    43. ht2.Insert(24);
    44. ht2.Insert(26);
    45. ht2.Insert(16);
    46. ht2.Erase(14);
    47. ht2.Erase(2);
    48. HashNode* Node2 = ht2.Find(4);*/
    49. }
    50. void TestOpenHash2()
    51. {
    52. using OPENHASH::_Hash;
    53. OPENHASH::HashTable,_Hash> ht;
    54. ht.Insert("sort");
    55. ht.Insert("futile");
    56. ht.Insert("plight");
    57. cout << ht.HashFunc("abcd") << endl;
    58. cout << ht.HashFunc("aadd") << endl;
    59. }
    60. int main()
    61. {
    62. //TestCloseHash();
    63. //TestOpenHash1();
    64. //TestOpenHash2();
    65. //mz::test_unordered_set();
    66. mz::test_unordered_map();
    67. return 0;
    68. }

    MyUnorderedSet.h:

    1. #pragma once
    2. #include"HashTable.h"
    3. using namespace OPENHASH;
    4. namespace mz
    5. {
    6. using OPENHASH::_Hash;
    7. template<class K, class Hash = _Hash>
    8. class unordered_set
    9. {
    10. struct SetKOfT
    11. {
    12. const K& operator()(const K& k)
    13. {
    14. return k;
    15. }
    16. };
    17. public:
    18. //加typename是告诉编译器这是个类型,你先让我过,等实例化了再去找
    19. //因为模板没实例化它是不接受你用模板里面的一个类型,故要用typename
    20. typedef typename HashTable::iterator iterator;
    21. iterator begin()
    22. {
    23. return _ht.begin();
    24. }
    25. iterator end()
    26. {
    27. return _ht.end();
    28. }
    29. pairbool> insert(const K& k)
    30. {
    31. return _ht.Insert(k);
    32. }
    33. private:
    34. HashTable _ht;
    35. };
    36. void test_unordered_set()
    37. {
    38. unordered_set<int> s;
    39. s.insert(1);
    40. s.insert(5);
    41. s.insert(4);
    42. s.insert(2);
    43. unordered_set<int>::iterator it = s.begin();
    44. while (it != s.end())
    45. {
    46. cout << *it << " ";
    47. ++it;
    48. }
    49. cout << endl;
    50. }
    51. }

    MyUnorderedMap.h:

    1. #pragma once
    2. #include"HashTable.h"
    3. using namespace OPENHASH;
    4. namespace mz
    5. {
    6. using OPENHASH::_Hash;
    7. template<class K, class V, class Hash = _Hash>//一般模板参数都是由上一层来控制的
    8. class unordered_map
    9. {
    10. struct MapKOfT
    11. {
    12. const K& operator()(const pair& kv)
    13. {
    14. return kv.first;
    15. }
    16. };
    17. public:
    18. typedef typename HashTable, MapKOfT, Hash>::iterator iterator;
    19. iterator begin()
    20. {
    21. return _ht.begin();
    22. }
    23. iterator end()
    24. {
    25. return _ht.end();
    26. }
    27. pairbool> insert(const pair& kv)
    28. {
    29. return _ht.Insert(kv);
    30. }
    31. V& operator[](const K& key)
    32. {
    33. pairbool> ret = _ht.Insert(make_pair(key, V()));
    34. return ret.first->second;
    35. }
    36. private:
    37. HashTable, MapKOfT, Hash> _ht;//底层是个哈希表
    38. };
    39. void test_unordered_map()
    40. {
    41. unordered_map dict;
    42. dict.insert(make_pair("factual", "真实的"));
    43. dict.insert(make_pair("fringe", "侵犯"));
    44. dict.insert(make_pair("intermittent", "间歇的"));
    45. dict["prerequisite"] = "先决条件";
    46. dict["reduce to"] = "处于";
    47. //unordered_map::iterator it = dict.begin();
    48. auto it = dict.begin();
    49. while (it != dict.end())
    50. {
    51. cout << it->first << ":" << it->second << endl;
    52. ++it;
    53. }
    54. cout << endl;
    55. }
    56. }

  • 相关阅读:
    数据结构之二叉搜索树
    Unity Shader顶点数据疑问
    ElasticSearch:实现高效数据搜索与分析的利器!项目中如何应用落地,让我带你实操指南。
    融云云盘,不止于存储
    【Vue】搭建vuex环境
    Git 详细安装教程(详解 Git 安装过程的每一个步骤)
    比Tensorflow还强?
    解决uniapp打包过大问题的实用方法
    ES5中实现继承
    CatFly【汇编代码还原】
  • 原文地址:https://blog.csdn.net/m0_74044018/article/details/133973253