• 哈希结构的实现


    目录

    unordered系列关联式容器

    哈希的简介

    哈希表闭散列实现

    哈希表开散列实现

    用哈希表来封装map和set

    位图

    布隆过滤器与哈希切割

    全部代码


    unordered系列关联式容器

    unordered系列关联式容器有四种,这里主要对unordered_map和unordered_set这两种容器进行介绍

    unordered_map

    unordered_map是存储<key, value>键值对的关联式容器,其允许通过keys快速的索引到与其对应的value

    在内部,unordered_map没有对<kye, value>按照任何特定的顺序排序

    unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低

    unordered_maps实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value

    unordered_set

    unordered_set和unordered_map在性质上差不多,因为底层结构是一致的,都是哈希结构,区别在与,unordered_set不支持[],因为它存储的是key与value相同,所以无需支持[]

    哈希的简介

    概念

    如果构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素

    哈希函数有多种,这里采用除留余数法

    哈希冲突

    比如14和4取模后都是4,而4对应的位置只能存储一个数字,那么就出现了哈希冲突,而解决哈希冲突的常见两种方法有闭散列和开散列

    哈希表闭散列实现

    闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到冲突位置中的“下一个” 空位置中去

    寻找下一空位置有线性探测和二次探测两种

    线性探测

    从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止

     二次探测

    从发生冲突的位置开始,跨越探测,直到寻找到下一个空位置为止

    index是哈希表的下标

    首先因为有闭散列和开散列两种,所以采用命名空间的形式来防止命名冲突

     

    然后定义一个枚举类型,用来判断该下标的空间的状态,是存在数据,还是删除过数据,或者没有数据,便于插入,删除,及查找数据

    封装节点,开始必然为每个下标所在的空间必然为空状态,所以初始化为空状态

     

    因为要是除留取余法,必然要是整数,所以还需要借助仿函数来实现

    内置类型

    string类型

    string类型转整形,可以将字符串的每个字母的ASCII码值加起来,但要是只是顺序不同,那总数也会相同,出现哈希冲突,为了尽量减少哈希冲突,就有了下图的方法,其中31是累乘因子

    string类型有下列两种写法,任选其一即可

    对于其它自定义类型,比如日期,则按照特定方式取整即可 

    哈希表同样采用模板的形式实现,另外私有成员有中的_n是有效数据个数,便于后续插入数据扩容使用

     

    查找数据

    如果表为空,则直接返回nullptr即可

    首先用待查找的key模表的长度取模作为待查找的初始下标,然后一直往后查找,同时往后走时,最后别忘了再取模一次,因为可能会存在初始下标空间的前面空间,找不到时,则直接返回nullptr

    删除数据

    首先先查找数据,找到数据了有效数据就减少一个,然后将那个节点的状态置为删除状态,删除成功返回true即可,没找到就表示删除失败,返回false

    插入数据

    首先先查找数据,如果存在,就表示待插入的数据已经有了,所以无需再插入,返回false即可

    根据有效数据个数,得到负载因子,如果负载因子大于等于0.7则表示需要扩容了,初始没有空间时,也一样需要扩容

    负载因子越小,冲突概率越低,效率越高,空间浪费越多

    负载因子越大,冲突概率越高,效率越低,空间浪费越少

    如果是初始时则开10个空间,其它情况则直接开原来的2倍空间

     

    创建一个新表,开辟新空间大小的空间,再将其数据拷贝到新表,然后将新表对象中的vector成员与this对象中的vector成员交换即可

    如果不需要开辟新空间

    则先将key取模,找到对应的下标,如果有空间,则直接插入数据,没有,则继续往后面找,与find()类似,最后有效数据+1,返回true即可

    闭散列最大的缺陷就是空间利用率比较低,这也是哈希的缺陷

    哈希表开散列实现

    概念

    开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中,开散列中每个桶中放的都是发生哈希冲突的元素,如下图

    封装节点,其实就是单链表的节点封装

     

    私有成员与闭散列一致,同时,还是采用除留去余法,所以会用到仿函数,与上面闭散列一致

    查找数据

    如果哈希表为空,则直接返回nullptr

    找到待查找的数据节点的下标,以及声明一个局部变量来保存这条链的头节点

    从头开始往后找,找到了返回节点地址,没找到返回nullptr

    删除数据

    如果哈希表为空,返回false,表示删除失败

    找到待删除数据节点的那条链的头节点

    如果找到了,则分为两种情况,如果就是头节点,那就直接头删,否则就中间删除

     

     如果没找到,则继续往后面找,找不到则返回false,表示删除失败

     插入数据

    首先先查找数据,如果存在,就表示待插入的数据已经有了,所以无需再插入,返回false即可

     

    如果负载因子等于1时,则需要扩容,初始开空间时开10个空间,其余情况开原来的2倍空间

    然后将原表的数据按头插拷贝到新表,将原表每条链的表头置空,最后再交换this对象的vector成员与新表的vector成员即可

    如果不需要扩容,则直接头插,然后将有效数据个数+1,再返回true即可

    为了减少哈希冲突,每次扩容后的空间大小都为素数

      

    用哈希表来封装map和set

    改善哈希表

    因为既要封装map,又要封装set,所以将数据类型从pair类型变为了T类型

    迭代器

    因为会用到哈希表,所以提前声明一下 

    因为要封装map和set,所以多加了一个模板参数KeyOfT,采用了仿函数

    因为map和set存储的数据不同,一个是pair<key,value>,一个是key所以对*和对->都要重载

    判断相不相等,比较的是节点的地址相不相等

    重载++运算符

    如果这条链上还有节点,即没有遇到nullptr,则直接往后走即可

    如果为nullptr,则从哈希表的下一个元素开始找,比如下图,走完11后,则继续往后面走,下一个元素表头为空,所以就走到了13,不为nullptr,则跳出循环

     

    如果是循环自动结束的,即走完整个哈希表了,则直接置nullptr即可

     

    如果是break出来的,则直接返回到那个节点,比如上述所说的13

     

    拷贝构造

    别忘了写一个默认构造函数,因为有了拷贝构造之后,编译器不会默认生成了

    这里采用的是头插法,所以顺序会有变化

    重载赋值运算符

    将实参传给形参时会有一次拷贝构造,所以只需将this对象的两个成员与形参的交换即可

    析构函数

    从哈希表第一个元素开始销毁节点,直到走完哈希表结束

    初始节点

    如果哈希表第一个元素的头节点不为nullptr,则它就是初始节点,否则直接返回nullptr的迭代器

    结尾节点,即nullptr

    重载[]运算符

    []可查找value,也可修改或插入

    位图

    位图的作用:数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在,比如在一堆数据中找5在不在,数据很多时,可以开辟整形最大值那么大的以bit为单位的空间,然后一个整数对应一个比特位,如果5对应的比特位是1,那就在这堆数据中,是0就不在

    1byte=8bit,所以开空间数如下图

    将某个bit位置为1

    将某个bit位置为0

    检查某个bit位是否为1

    0为假,非0为真

    位图:节省空间,效率高,但只能处理整数

    布隆过滤器与哈希切割

    概念

    布隆过滤器是由布隆在1970年提出的 一种紧凑型的、比较巧妙的概率型数据结构,特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中。既可以提升查询效率,也可以节省大量的内存空间

    作用:用来解决字符串,自定义类型对象在不在的问题

    如果采用将字符串转整数,即将字符串的各个字符加起来取模作为下标,那就可能会存在哈希冲突,比如下图中eat和ate

    这种方式,判断不在是准确的,比如eat和ate那个位置的比特位为0,则eat肯定不在,只是判断在会存在误判

    解决方式

    将一个元素用多个哈希函数映射到一个位图中,比如ate,只要三个种有一个bit位为0,则就表示ate不在,降低了误判率

    这里以哈希函数中三个不同的哈希函数为例模板参数

    1. //hashTable-副本
    2. #pragma once
    3. #include<vector>
    4. template<class K>
    5. struct Hash
    6. {
    7. size_t operator()(const K& key)
    8. {
    9. return key;
    10. }
    11. };
    12. //特化
    13. template<>
    14. struct Hash< string >
    15. {
    16. size_t operator()(const string& s)
    17. {
    18. //BKDR
    19. size_t value = 0;
    20. for (auto ch : s)
    21. {
    22. value *= 31;
    23. value += ch;
    24. }
    25. return value;
    26. }
    27. };
    28. namespace CloseHash
    29. {
    30. enum Status
    31. {
    32. EXIST,
    33. EMPTY,
    34. DELETE
    35. };
    36. template<class K,class V>
    37. struct HashData
    38. {
    39. pair<K, V> _kv;
    40. Status _status = EMPTY;
    41. };
    42. struct HashStr
    43. {
    44. size_t operator()(const string& s)
    45. {
    46. //BKDR
    47. size_t value = 0;
    48. for (auto ch : s)
    49. {
    50. value *= 31;
    51. value += ch;
    52. }
    53. return value;
    54. }
    55. };
    56. template<class K,class V,class HashFunc = Hash<K>>
    57. class HashTable
    58. {
    59. public:
    60. bool Erase(const K& key)
    61. {
    62. HashData<K, V>* ret = Find(key);
    63. if (ret == nullptr)
    64. {
    65. return false;
    66. }
    67. else
    68. {
    69. --_n;
    70. ret->_status = DELETE;
    71. return true;
    72. }
    73. }
    74. HashData<K, V>* Find(const K& key)
    75. {
    76. if (_tables.size() == 0)
    77. {
    78. return nullptr;
    79. }
    80. HashFunc hf;
    81. size_t start = hf(key) % _tables.size();
    82. size_t i = 0;
    83. size_t index = start;
    84. //线性探测 or 二次探测
    85. while (_tables[index]._status != EMPTY)
    86. {
    87. if (_tables[index]._kv.first == key && _tables[index]._status == EXIST)
    88. {
    89. return &_tables[index];
    90. }
    91. ++i;
    92. //index = start + i*i;
    93. index = start + i;
    94. index %= _tables.size();
    95. }
    96. return nullptr;
    97. }
    98. bool Insert(const pair<K, V>& kv)
    99. {
    100. HashData<K, V>* ret = Find(kv.first);
    101. if (ret)
    102. {
    103. return false;
    104. }
    105. //负载因子到0.7,就扩容
    106. //负载因子越小,冲突概率越低,效率越高,空间浪费越多
    107. //负载因子越大,冲突概率越高,效率越低,空间浪费越少
    108. if (_tables.size() == 0 || _n * 10 / _tables.size() >= 7)
    109. {
    110. //扩容
    111. size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
    112. //vector<HashData<K,V>> newTables;
    113. //newTables.resize(newSize);
    114. //遍历原表,把原表中的数据,重新按newSize映射到新表
    115. //for(size_t i = 0;i < _tables.size();++i)
    116. //{
    117. //
    118. //}
    119. //_tables.swap(newTables);
    120. HashTable<K, V, HashFunc> newHT;
    121. newHT._tables.resize(newSize);
    122. for (size_t i = 0; i < _tables.size(); ++i)
    123. {
    124. if (_tables[i]._status == EXIST)
    125. {
    126. newHT.Insert(_tables[i]._kv);
    127. }
    128. }
    129. _tables.swap(newHT._tables);
    130. }
    131. HashFunc hf;
    132. size_t start = hf(kv.first) % _tables.size();
    133. size_t i = 0;
    134. size_t index = start;
    135. //线性探测 or 二次探测
    136. while (_tables[index]._status == EXIST)
    137. {
    138. ++i;
    139. //index = start + i * i;
    140. index = start + i;
    141. index %= _tables.size();
    142. }
    143. _tables[index]._kv = kv;
    144. _tables[index]._status = EXIST;
    145. ++_n;
    146. return true;
    147. }
    148. private:
    149. vector<HashData<K, V>> _tables;
    150. size_t _n = 0;//有效数据个数
    151. };
    152. void TestHashTable1()
    153. {
    154. //HashTable<int,int,Hash<int>> ht;
    155. HashTable<int, int> ht;
    156. int a[] = { 2,12,22,32,42,52,62 };
    157. for (auto e : a)
    158. {
    159. ht.Insert(make_pair(e, e));
    160. }
    161. ht.Insert(make_pair(72, 72));
    162. ht.Insert(make_pair(72, 72));
    163. ht.Insert(make_pair(-1, -1));
    164. ht.Insert(make_pair(-999, -999));
    165. Hash<int> hs;
    166. cout << hs(9) << endl;
    167. cout << hs(-9) << endl;
    168. cout << ht.Find(12) << endl;
    169. ht.Erase(12);
    170. cout << ht.Find(12) << endl;
    171. }
    172. struct Date
    173. {
    174. };
    175. struct HashDate
    176. {
    177. size_t operator()(const Date& d)
    178. {
    179. //...
    180. }
    181. };
    182. void TestHashTable2()
    183. {
    184. HashStr hs;
    185. cout << hs("sort") << endl;
    186. cout << hs("insert") << endl;
    187. cout << hs("eat") << endl;
    188. cout << hs("ate") << endl;
    189. cout << hs("abcd") << endl;
    190. cout << hs("aadd") << endl;
    191. HashTable<string, string> ht;
    192. ht.Insert(make_pair("sort", "排序"));
    193. ht.Insert(make_pair("string", "字符串"));
    194. //当key是一个定义类型时,需要配置一个仿函数,将key转成整形
    195. HashTable<Date, string, HashDate> htds;
    196. }
    197. }
    198. namespace LinkHash
    199. {
    200. template<class K,class V>
    201. struct HashNode
    202. {
    203. pair<K, V> _kv;
    204. HashNode<K, V>* _next;
    205. HashNode(const pair<K, V>& kv):_kv(kv),_next(nullptr)
    206. {}
    207. };
    208. template<class K,class V,class HashFunc = Hash<K>>
    209. class HashTable
    210. {
    211. typedef HashNode<K, V> Node;
    212. public:
    213. bool Erase(const K& key)
    214. {
    215. if (_tables.empty())
    216. {
    217. return false;
    218. }
    219. HashFunc hf;
    220. size_t index = hf(key) % _tables.size();
    221. Node* prev = nullptr;
    222. Node* cur = _tables[index];
    223. while (cur)
    224. {
    225. if (cur->_kv.first == key)
    226. {
    227. if (prev == nullptr) //头删
    228. {
    229. _tables[index] = cur->_next;
    230. }
    231. else //中间删除
    232. {
    233. prev->_next = cur->_next;
    234. }
    235. --_n;
    236. delete cur;
    237. return true;
    238. }
    239. else
    240. {
    241. prev = cur;
    242. cur = cur->_next;
    243. }
    244. }
    245. return false;
    246. }
    247. Node* Find(const K& key)
    248. {
    249. if (_tables.empty())
    250. {
    251. return nullptr;
    252. }
    253. HashFunc hf;
    254. size_t index = hf(key) % _tables.size();
    255. Node* cur = _tables[index];
    256. while (cur)
    257. {
    258. if (cur->_kv.first == key)
    259. {
    260. return cur;
    261. }
    262. else
    263. {
    264. cur = cur->_next;
    265. }
    266. }
    267. return nullptr;
    268. }
    269. bool Insert(const pair<K, V>& kv)
    270. {
    271. Node* ret = Find(kv.first);
    272. if (ret)
    273. return false;
    274. HashFunc hf;
    275. if (_n == _tables.size())
    276. {
    277. size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
    278. //...
    279. vector<Node*> newTables;
    280. newTables.resize(newSize);
    281. for (size_t i = 0; i < _tables.size(); ++i)
    282. {
    283. Node* cur = _tables[i];
    284. while (cur)
    285. {
    286. Node* next = cur->_next;
    287. size_t index = hf(cur->_kv.first) % newTables.size();
    288. //头插
    289. cur->_next = newTables[index];
    290. newTables[index] = cur;
    291. cur = next;
    292. }
    293. _tables[i] = nullptr;
    294. }
    295. _tables.swap(newTables);
    296. }
    297. size_t index = hf(kv.first) % _tables.size();
    298. Node* newnode = new Node(kv);
    299. //头插
    300. newnode->_next = _tables[index];
    301. _tables[index] = newnode;
    302. ++_n;
    303. return true;
    304. }
    305. private:
    306. /*struct Data
    307. {
    308. forward_list<T> _list;
    309. set<T> _rbtree;
    310. size_t len;
    311. };
    312. vector<Data> _table;*/
    313. vector<Node*> _tables;
    314. size_t _n = 0;//有效数据的个数
    315. };
    316. void TestHashTable()
    317. {
    318. int a[] = { 4,24,14,7,37,27,57,67,34,14,54 };
    319. HashTable<int, int> ht;
    320. for (auto e : a)
    321. {
    322. ht.Insert(make_pair(e, e));
    323. }
    324. ht.Insert(make_pair(84, 84));
    325. }
    326. };
    327. //hashTable
    328. #pragma once
    329. #include<vector>
    330. #include<string>
    331. template<class K>
    332. struct Hash
    333. {
    334. size_t operator()(const K& key)
    335. {
    336. return key;
    337. }
    338. };
    339. //特化
    340. template<>
    341. struct Hash< string >
    342. {
    343. size_t operator()(const string& s)
    344. {
    345. //BKDR
    346. size_t value = 0;
    347. for (auto ch : s)
    348. {
    349. value *= 31;
    350. value += ch;
    351. }
    352. return value;
    353. }
    354. };
    355. namespace CloseHash
    356. {
    357. enum Status
    358. {
    359. EXIST,
    360. EMPTY,
    361. DELETE
    362. };
    363. template<class K, class V>
    364. struct HashData
    365. {
    366. pair<K, V> _kv;
    367. Status _status = EMPTY;
    368. };
    369. //struct HashStr
    370. //{
    371. // size_t operator()(const string& s)
    372. // {
    373. // //BKDR
    374. // size_t value = 0;
    375. // for (auto ch : s)
    376. // {
    377. // value *= 31;
    378. // value += ch;
    379. // }
    380. // return value;
    381. // }
    382. //};
    383. template<class K, class V, class HashFunc = Hash<K>>
    384. class HashTable
    385. {
    386. public:
    387. bool Erase(const K& key)
    388. {
    389. HashData<K, V>* ret = Find(key);
    390. if (ret == nullptr)
    391. {
    392. return false;
    393. }
    394. else
    395. {
    396. --_n;
    397. ret->_status = DELETE;
    398. return true;
    399. }
    400. }
    401. HashData<K, V>* Find(const K& key)
    402. {
    403. if (_tables.size() == 0)
    404. {
    405. return nullptr;
    406. }
    407. HashFunc hf;
    408. size_t start = hf(key) % _tables.size();
    409. size_t i = 0;
    410. size_t index = start;
    411. //线性探测 or 二次探测
    412. while (_tables[index]._status != EMPTY)
    413. {
    414. if (_tables[index]._kv.first == key && _tables[index]._status == EXIST)
    415. {
    416. return &_tables[index];
    417. }
    418. ++i;
    419. //index = start + i*i;
    420. index = start + i;
    421. index %= _tables.size();
    422. }
    423. return nullptr;
    424. }
    425. bool Insert(const pair<K, V>& kv)
    426. {
    427. HashData<K, V>* ret = Find(kv.first);
    428. if (ret)
    429. {
    430. return false;
    431. }
    432. //负载因子到0.7,就扩容
    433. //负载因子越小,冲突概率越低,效率越高,空间浪费越多
    434. //负载因子越大,冲突概率越高,效率越低,空间浪费越少
    435. if (_tables.size() == 0 || _n * 10 / _tables.size() >= 7)
    436. {
    437. //扩容
    438. size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
    439. //vector<HashData<K,V>> newTables;
    440. //newTables.resize(newSize);
    441. //遍历原表,把原表中的数据,重新按newSize映射到新表
    442. //for(size_t i = 0;i < _tables.size();++i)
    443. //{
    444. //
    445. //}
    446. //_tables.swap(newTables);
    447. HashTable<K, V, HashFunc> newHT;
    448. newHT._tables.resize(newSize);
    449. for (size_t i = 0; i < _tables.size(); ++i)
    450. {
    451. if (_tables[i]._status == EXIST)
    452. {
    453. newHT.Insert(_tables[i]._kv);
    454. }
    455. }
    456. _tables.swap(newHT._tables);
    457. }
    458. HashFunc hf;
    459. size_t start = hf(kv.first) % _tables.size();
    460. size_t i = 0;
    461. size_t index = start;
    462. //线性探测 or 二次探测
    463. while (_tables[index]._status == EXIST)
    464. {
    465. ++i;
    466. //index = start + i * i;
    467. index = start + i;
    468. index %= _tables.size();
    469. }
    470. _tables[index]._kv = kv;
    471. _tables[index]._status = EXIST;
    472. ++_n;
    473. return true;
    474. }
    475. private:
    476. vector<HashData<K, V>> _tables;
    477. size_t _n = 0;//有效数据个数
    478. };
    479. void TestHashTable1()
    480. {
    481. //HashTable<int,int,Hash<int>> ht;
    482. HashTable<int, int> ht;
    483. int a[] = { 2,12,22,32,42,52,62 };
    484. for (auto e : a)
    485. {
    486. ht.Insert(make_pair(e, e));
    487. }
    488. ht.Insert(make_pair(72, 72));
    489. ht.Insert(make_pair(72, 72));
    490. ht.Insert(make_pair(-1, -1));
    491. ht.Insert(make_pair(-999, -999));
    492. Hash<int> hs;
    493. cout << hs(9) << endl;
    494. cout << hs(-9) << endl;
    495. cout << ht.Find(12) << endl;
    496. ht.Erase(12);
    497. cout << ht.Find(12) << endl;
    498. }
    499. struct Date
    500. {
    501. };
    502. struct HashDate
    503. {
    504. size_t operator()(const Date& d)
    505. {
    506. //...
    507. }
    508. };
    509. void TestHashTable2()
    510. {
    511. /*HashStr hs;
    512. cout << hs("sort") << endl;
    513. cout << hs("insert") << endl;
    514. cout << hs("eat") << endl;
    515. cout << hs("ate") << endl;
    516. cout << hs("abcd") << endl;
    517. cout << hs("aadd") << endl;*/
    518. HashTable<string, string> ht;
    519. ht.Insert(make_pair("sort", "排序"));
    520. ht.Insert(make_pair("string", "字符串"));
    521. //当key是一个定义类型时,需要配置一个仿函数,将key转成整形
    522. HashTable<Date, string, HashDate> htds;
    523. }
    524. }
    525. namespace LinkHash
    526. {
    527. template<class T>
    528. struct HashNode
    529. {
    530. T _data;
    531. HashNode<T>* _next;
    532. HashNode(const T& data) :_data(data), _next(nullptr)
    533. {}
    534. };
    535. template<class K, class T,class KeyOfT, class HashFunc>
    536. class HashTable;
    537. template<class K,class T,class Ref,class Ptr,class KeyOfT,class HashFunc>
    538. struct __HTIterator
    539. {
    540. typedef HashNode<T> Node;
    541. typedef __HTIterator<K, T, Ref, Ptr, KeyOfT, HashFunc> Self;
    542. Node* _node;
    543. HashTable<K, T, KeyOfT, HashFunc>* _pht;
    544. __HTIterator(Node* node,HashTable<K,T,KeyOfT,HashFunc>* pht):_node(node),_pht(pht)
    545. {}
    546. Ref operator*()
    547. {
    548. return _node->_data;
    549. }
    550. Ptr operator->()
    551. {
    552. return &_node->_data;
    553. }
    554. Self& operator++()
    555. {
    556. if (_node->_next)
    557. {
    558. _node = _node->_next;
    559. }
    560. else
    561. {
    562. KeyOfT kot;
    563. HashFunc hf;
    564. size_t index = hf(kot(_node->_data)) % _pht->_tables.size();
    565. ++index;
    566. //找下一个不为空的值
    567. while (index < _pht->_tables.size())
    568. {
    569. if (_pht->_tables[index])
    570. {
    571. break;
    572. }
    573. else
    574. {
    575. ++index;
    576. }
    577. }
    578. //表走完了,都没有找到下一个桶
    579. if (index == _pht->_tables.size())
    580. {
    581. _node = nullptr;
    582. }
    583. else
    584. {
    585. _node = _pht->_tables[index];
    586. }
    587. }
    588. return *this;
    589. }
    590. bool operator!=(const Self& s) const
    591. {
    592. return _node != s._node;
    593. }
    594. bool operator==(const Self& s) const
    595. {
    596. return _node = s._node;
    597. }
    598. };
    599. template<class K,class T,class KeyOfT,class HashFunc>
    600. class HashTable
    601. {
    602. typedef HashNode<T> Node;
    603. template<class K,class T,class Ref,class Ptr,class KeyOfT,class HashFunc>
    604. friend struct __HTIterator;
    605. typedef HashTable<K, T, KeyOfT, HashFunc> self;
    606. public:
    607. typedef __HTIterator<K, T, T&, T*, KeyOfT, HashFunc> iterator;
    608. HashTable()
    609. {}
    610. //显示指定编译器去生成默认构造函数
    611. //HashTable() = default;
    612. HashTable(const self& ht)
    613. {
    614. _tables.resize(ht._tables.size());
    615. for (size_t i = 0; i < ht._tables.size(); ++i)
    616. {
    617. Node* cur = ht._tables[i];
    618. while (cur)
    619. {
    620. Node* copy = new Node(cur->_data);
    621. copy->_next = _tables[i];
    622. _tables[i] = copy;
    623. cur = cur->_next;
    624. }
    625. }
    626. }
    627. //ht1 = ht2
    628. self& operator=(self copy)
    629. {
    630. swap(_n, copy._n);
    631. _tables.swap(copy._tables);
    632. return *this;
    633. }
    634. ~HashTable()
    635. {
    636. for (size_t i = 0; i < _tables.size(); ++i)
    637. {
    638. Node* cur = _tables[i];
    639. while (cur)
    640. {
    641. Node* next = cur->_next;
    642. delete cur;
    643. cur = next;
    644. }
    645. _tables[i] = nullptr;
    646. }
    647. }
    648. iterator begin()
    649. {
    650. for (size_t i = 0; i < _tables.size(); ++i)
    651. {
    652. if (_tables[i])
    653. {
    654. return iterator(_tables[i], this);
    655. }
    656. }
    657. return end();
    658. }
    659. iterator end()
    660. {
    661. return iterator(nullptr, this);
    662. }
    663. bool Erase(const K& key)
    664. {
    665. if (_tables.empty())
    666. {
    667. return false;
    668. }
    669. HashFunc hf;
    670. size_t index = hf(key) % _tables.size();
    671. Node* prev = nullptr;
    672. Node* cur = _tables[index];
    673. KeyOfT kot;
    674. while (cur)
    675. {
    676. if (kot(cur->_data) == key)
    677. {
    678. if (prev == nullptr) //头删
    679. {
    680. _tables[index] = cur->_next;
    681. }
    682. else //中间删除
    683. {
    684. prev->_next = cur->_next;
    685. }
    686. --_n;
    687. delete cur;
    688. return true;
    689. }
    690. else
    691. {
    692. prev = cur;
    693. cur = cur->_next;
    694. }
    695. }
    696. return false;
    697. }
    698. iterator Find(const K& key)
    699. {
    700. if (_tables.empty())
    701. {
    702. return end();
    703. }
    704. HashFunc hf;
    705. size_t index = hf(key) % _tables.size();
    706. Node* cur = _tables[index];
    707. KeyOfT kot;
    708. while (cur)
    709. {
    710. if (kot(cur->_data) == key)
    711. {
    712. return iterator(cur,this);
    713. }
    714. else
    715. {
    716. cur = cur->_next;
    717. }
    718. }
    719. return end();
    720. }
    721. size_t GetNextPrime(size_t num)
    722. {
    723. static const unsigned long __stl_prime_list[28] =
    724. {
    725. 53,97,193,389,769,
    726. 1543,3079,6151,12289,24593,
    727. 49157,98317,196613,393241,786433,
    728. 1572869,3145739,6291469,12582917,25165843,
    729. 50331653,100663319,201326611,402653189,805306457,
    730. 1610612741,3221225473,4294967291
    731. };
    732. for(size_t i = 0;i < 28;++i)
    733. {
    734. if (__stl_prime_list[i] > num)
    735. {
    736. return __stl_prime_list[i];
    737. }
    738. }
    739. return __stl_prime_list[27];
    740. }
    741. pair<iterator,bool> Insert(const T& data)
    742. {
    743. KeyOfT kot;
    744. iterator ret = Find(kot(data));
    745. if (ret != end())
    746. return make_pair(ret,false);
    747. HashFunc hf;
    748. //负载因子 == 1时扩容
    749. if (_n == _tables.size())
    750. {
    751. //size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
    752. //...
    753. size_t newSize = GetNextPrime(_tables.size());
    754. /*if (newSize == _tables.size())
    755. {
    756. break;
    757. }*/
    758. vector<Node*> newTables;
    759. newTables.resize(newSize);
    760. for (size_t i = 0; i < _tables.size(); ++i)
    761. {
    762. Node* cur = _tables[i];
    763. while (cur)
    764. {
    765. Node* next = cur->_next;
    766. size_t index = hf(kot(cur->_data)) % newTables.size();
    767. //头插
    768. cur->_next = newTables[index];
    769. newTables[index] = cur;
    770. cur = next;
    771. }
    772. _tables[i] = nullptr;
    773. }
    774. _tables.swap(newTables);
    775. }
    776. size_t index = hf(kot(data)) % _tables.size();
    777. Node* newnode = new Node(data);
    778. //头插
    779. newnode->_next = _tables[index];
    780. _tables[index] = newnode;
    781. ++_n;
    782. return make_pair(iterator(newnode,this),false);
    783. }
    784. private:
    785. /*struct Data
    786. {
    787. forward_list<T> _list;
    788. set<T> _rbtree;
    789. size_t len;
    790. };
    791. vector<Data> _table;*/
    792. vector<Node*> _tables;
    793. size_t _n = 0;//有效数据的个数
    794. };
    795. }
    796. //unordered-map
    797. #pragma once
    798. #include"HashTable.h"
    799. namespace bit
    800. {
    801. template<class K,class V,class hash = Hash<K>>
    802. class unordered_map
    803. {
    804. struct MapKeyOfT
    805. {
    806. const K& operator()(const pair<K, V>& kv)
    807. {
    808. return kv.first;
    809. }
    810. };
    811. public:
    812. typedef typename LinkHash::HashTable<K, pair<K, V>, MapKeyOfT, hash>::iterator iterator;
    813. iterator begin()
    814. {
    815. return _ht.begin();
    816. }
    817. iterator end()
    818. {
    819. return _ht.end();
    820. }
    821. V& operator[](const K& key)
    822. {
    823. auto ret = _ht.Insert(make_pair(key, V()));
    824. return ret.first->second;
    825. }
    826. pair<iterator,bool> insert(const pair<K, V>& kv)
    827. {
    828. return _ht.Insert(kv);
    829. }
    830. private:
    831. LinkHash::HashTable<K, pair<K,V>, MapKeyOfT, hash > _ht;
    832. };
    833. void test_unordered_map()
    834. {
    835. unordered_map<string, string> dict;
    836. dict.insert(make_pair("sort", "排序"));
    837. dict.insert(make_pair("string", "字符串"));
    838. dict.insert(make_pair("map", "地图、映射"));
    839. /*cout << dict["sort"] << endl;
    840. cout << dict["string"] << endl;
    841. cout << dict["map"] << endl;*/
    842. //dict["right"] = "右边";
    843. unordered_map<string, string>::iterator it = dict.begin();
    844. while (it != dict.end())
    845. {
    846. cout << it->first << ":" << it->second << endl;
    847. ++it;
    848. }
    849. cout << endl;
    850. unordered_map<string, string> copy(dict);
    851. for (auto& kv : copy)
    852. {
    853. cout << kv.first << ":" << kv.second << endl;
    854. }
    855. cout << endl;
    856. }
    857. }
    858. //unordered-set
    859. #pragma once
    860. namespace bit
    861. {
    862. template<class K,class hash = Hash<K>>
    863. class unordered_set
    864. {
    865. struct SetKeyOfT
    866. {
    867. const K& operator()(const K& key)
    868. {
    869. return key;
    870. }
    871. };
    872. public:
    873. typedef typename LinkHash::HashTable<K, K, SetKeyOfT, hash>::iterator iterator;
    874. iterator begin()
    875. {
    876. return _ht.begin();
    877. }
    878. iterator end()
    879. {
    880. return _ht.end();
    881. }
    882. pair<iterator,bool> insert(const K& key)
    883. {
    884. return _ht.Insert(key);
    885. }
    886. private:
    887. LinkHash::HashTable<K, K, SetKeyOfT, hash> _ht;
    888. };
    889. void test_unordered_set()
    890. {
    891. unordered_set<int> us;
    892. us.insert(4);
    893. us.insert(14);
    894. us.insert(34);
    895. us.insert(7);
    896. us.insert(24);
    897. us.insert(17);
    898. unordered_set<int>::iterator it = us.begin();
    899. while (it != us.end())
    900. {
    901. cout << *it << " ";
    902. ++it;
    903. }
    904. cout << endl;
    905. unordered_set<int> uss(us);
    906. unordered_set<int>::iterator It = uss.begin();
    907. while (It != uss.end())
    908. {
    909. cout << *It << " ";
    910. ++It;
    911. }
    912. cout << endl;
    913. /*unordered_set<string> uss;
    914. uss.insert("sort");
    915. uss.insert("hash");*/
    916. /*unordered_set<int> us;
    917. for (size_t i = 0; i < 100; ++i)
    918. {
    919. us.insert(i);
    920. }*/
    921. }
    922. }
    923. //bitSet
    924. #pragma once
    925. #include<vector>
    926. namespace bit
    927. {
    928. template<size_t N>
    929. class bitset
    930. {
    931. public:
    932. bitset()
    933. {
    934. _bits.resize(N / 8 + 1, 0);
    935. }
    936. void set(size_t x)
    937. {
    938. size_t i = x / 8;
    939. size_t j = x % 8;
    940. _bits[i] |= (1 << j);
    941. }
    942. void reset(size_t x)
    943. {
    944. size_t i = x / 8;
    945. size_t j = x % 8;
    946. _bits[i] &= (~(1 << j));
    947. }
    948. bool test(size_t x)
    949. {
    950. size_t i = x / 8;
    951. size_t j = x % 8;
    952. return _bits[i] & (1 << j);
    953. }
    954. private:
    955. std::vector<char> _bits;
    956. //std::vector<int> _bits;
    957. };
    958. void test_bitset()
    959. {
    960. bitset<100> bs;
    961. bs.set(5);
    962. bs.set(4);
    963. bs.set(10);
    964. bs.set(20);
    965. cout << bs.test(5) << endl;
    966. cout << bs.test(4) << endl;
    967. cout << bs.test(10) << endl;
    968. cout << bs.test(20) << endl;
    969. cout << bs.test(21) << endl;
    970. cout << bs.test(6) << endl << endl;
    971. bs.reset(20);
    972. bs.reset(10);
    973. bs.reset(5);
    974. cout << bs.test(5) << endl;
    975. cout << bs.test(4) << endl;
    976. cout << bs.test(10) << endl;
    977. cout << bs.test(20) << endl;
    978. cout << bs.test(21) << endl;
    979. cout << bs.test(6) << endl;
    980. //bitset<0xffffffff> bs;
    981. //bitset<-1> bs;
    982. }
    983. }
    984. template<size_t N>
    985. class TwoBitSet
    986. {
    987. public:
    988. void Set(size_t x)
    989. {
    990. if (!_bs1.test(x) && !_bs2.test(x)) //00 -> 01
    991. {
    992. _bs2.set(x);
    993. }
    994. else if (!_bs1.test(x) && _bs2.test(x)) //01 -> 10
    995. {
    996. _bs1.set(x);
    997. _bs2.reset(x);
    998. }
    999. //10 表示已经出现2次或以上,不用处理
    1000. }
    1001. void PrintOnceNum()
    1002. {
    1003. for (size_t i = 0; i < N; ++i)
    1004. {
    1005. if (!_bs1.test(i) && _bs2.test(i)) // 01
    1006. {
    1007. cout << i << endl;
    1008. }
    1009. }
    1010. }
    1011. private:
    1012. bit::bitset<N> _bs1;
    1013. bit::bitset<N> _bs2;
    1014. };
    1015. void TestTwoBitSet()
    1016. {
    1017. int a[] = { 99,0,4,50,33,44,2,5,99,0,50,99,50,2 };
    1018. TwoBitSet<100> bs;
    1019. for (auto e : a)
    1020. {
    1021. bs.Set(e);
    1022. }
    1023. bs.PrintOnceNum();
    1024. }
    1025. void TestFindIntersection()
    1026. {
    1027. int a1[] = { 5,30,1,99,10 };
    1028. int a2[] = { 8,10,11,9,30,10,30 };
    1029. }
    1030. //BloomFilter
    1031. #pragma once
    1032. #include<bitset>
    1033. #include<string>
    1034. #include<time.h>
    1035. struct BKDRHash
    1036. {
    1037. size_t operator()(const string& s)
    1038. {
    1039. //BKDR
    1040. size_t value = 0;
    1041. for (auto ch : s)
    1042. {
    1043. value *= 3;
    1044. value += ch;
    1045. }
    1046. return value;
    1047. }
    1048. };
    1049. struct APHash
    1050. {
    1051. size_t operator()(const string& s)
    1052. {
    1053. size_t hash = 0;
    1054. for (long i = 0; i < s.size(); i++)
    1055. {
    1056. if ((i & 1) == 0)
    1057. {
    1058. hash ^= ((hash << 7) ^ s[i] ^ (hash >> 3));
    1059. }
    1060. else
    1061. {
    1062. hash ^= (~((hash << 11) ^ s[i] ^ (hash >> 5)));
    1063. }
    1064. }
    1065. return hash;
    1066. }
    1067. };
    1068. struct DJBHash
    1069. {
    1070. size_t operator()(const string& s)
    1071. {
    1072. size_t hash = 5381;
    1073. for(auto ch : s)
    1074. {
    1075. hash += (hash << 5) + ch;
    1076. }
    1077. return hash;
    1078. }
    1079. };
    1080. template<size_t N,
    1081. size_t X = 8,
    1082. class K = string,
    1083. class HashFunc1 = BKDRHash,
    1084. class HashFunc2 = APHash,
    1085. class HashFunc3 = DJBHash>
    1086. class BloomFilter
    1087. {
    1088. public:
    1089. void Set(const K& key)
    1090. {
    1091. size_t len = X * N;
    1092. size_t index1 = HashFunc1()(key) % len;
    1093. size_t index2 = HashFunc2()(key) % len;
    1094. size_t index3 = HashFunc3()(key) % len;
    1095. cout << index1 << endl;
    1096. cout << index2 << endl;
    1097. cout << index3 << endl << endl;
    1098. _bs.set(index1);
    1099. _bs.set(index2);
    1100. _bs.set(index3);
    1101. }
    1102. bool Test(const K& key)
    1103. {
    1104. size_t len = X * N;
    1105. size_t index1 = HashFunc1()(key) % len;
    1106. if (_bs.test(index1) == false)
    1107. return false;
    1108. size_t index2 = HashFunc2()(key) % len;
    1109. if (_bs.test(index2) == false)
    1110. return false;
    1111. size_t index3 = HashFunc3()(key) % len;
    1112. if (_bs.test(index3) == false)
    1113. return false;
    1114. return true; //存在误判的
    1115. }
    1116. //不支持删除,删除可能会影响其它值。
    1117. void Reset(const K& key);
    1118. private:
    1119. bitset<X* N> _bs;
    1120. };
    1121. void TestBloomFilter1()
    1122. {
    1123. BloomFilter<100> bm;
    1124. bm.Set("sort");
    1125. bm.Set("left");
    1126. bm.Set("right");
    1127. bm.Set("eat");
    1128. bm.Set("ate");
    1129. bm.Set("https://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html");
    1130. }
    1131. void TestBloomFilter2()
    1132. {
    1133. BloomFilter<100> bf;
    1134. bf.Set("张三");
    1135. bf.Set("李四");
    1136. bf.Set("牛魔王");
    1137. bf.Set("红孩儿");
    1138. bf.Set("eat");
    1139. cout << bf.Test("张三") << endl;
    1140. cout << bf.Test("李四") << endl;
    1141. cout << bf.Test("牛魔王") << endl;
    1142. cout << bf.Test("红孩儿") << endl;
    1143. cout << bf.Test("孙悟空") << endl;
    1144. cout << bf.Test("二郎神") << endl;
    1145. cout << bf.Test("猪八戒") << endl;
    1146. cout << bf.Test("ate") << endl;
    1147. //BloomFilter<100> bf;
    1148. srand(time(0));
    1149. size_t N = 100;
    1150. std::vector<std::string> v1;
    1151. for (size_t i = 0; i < N; ++i)
    1152. {
    1153. std::string ur1 = "https://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html";
    1154. ur1 += std::to_string(1234 + i);
    1155. v1.push_back(ur1);
    1156. }
    1157. for (auto& str : v1)
    1158. {
    1159. bf.Set(str);
    1160. }
    1161. for (auto& str : v1)
    1162. {
    1163. cout << bf.Test(str) << endl;
    1164. }
    1165. cout << endl << endl;
    1166. std::vector<std::string> v2;
    1167. for (size_t i = 0; i < N; ++i)
    1168. {
    1169. std::string ur1 = "https://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html";
    1170. ur1 += std::to_string(6789 + i);
    1171. v2.push_back(ur1);
    1172. }
    1173. size_t n2 = 0;
    1174. for (auto& str : v2)
    1175. {
    1176. if (bf.Test(str))
    1177. {
    1178. ++n2;
    1179. }
    1180. }
    1181. cout << "相似字符串误判率:" << (double)n2 / (double)N << endl;
    1182. std::vector<std::string> v3;
    1183. for (size_t i = 0; i < N; ++i)
    1184. {
    1185. string ur1 = "zhihu.com";
    1186. //std::string ur1 = "https://mail.qq.com/cgi-bin/frame_html?sid=0QvJ6bvfhn3EC1Iw&r=5976c09322eae24513a5ff315428cd86&lang=zh";
    1187. //std::string ur1 = "https://www.sogou.com/tx?query=%E5%88%98%E5%BC%BA%E4%B8%9C%E4%BA%8B%E4%BB%B6%20%E5%A5%B3%E6%96%B9%E7%A7%B0%E8%87%AA%E6%84%BF%E5%8F%91%E7%94%9F%E5%85%B3%E7%B3%BB&hdq=sogou-site-706608cfdbcc1886&ekv=3&ie=utf8&";
    1188. //std::string ur1 = "https://www.sogou.com/sogou?ie=utf8&pid=sogou-wsse-af64b05ee108fa0c&query=%E4%BA%BA%E6%B0%91%E7%BD%91%3A%E5%BE%B7%E4%BA%91%E7%A4%BE%E8%AF%A5%E8%87%AA%E6%88%91%E6%A3%80%E8%A7%86%E4%BA%86";
    1189. ur1 += std::to_string(rand());
    1190. v3.push_back(ur1);
    1191. }
    1192. size_t n3 = 0;
    1193. for (auto& str : v3)
    1194. {
    1195. if (bf.Test(str))
    1196. {
    1197. ++n3;
    1198. }
    1199. }
    1200. cout << "不相似字符串误判率:" << (double)n3 / (double)N << endl;
    1201. }

    设置为1

    首先先用三个哈希函数算出对应的下标

    再复用前面的位图的函数将其bit位设为1即可 

     

    注意:当len越大时,即空间开的越大时,误判率会越低

    检查在不在

    三个bit位,只要有一个bit位为0,则表示不在

    注意:布隆过滤器不支持删除,因为支持删除会消耗很多空间,而且会存在误删,比如上图中的ate和eat,如果删除ate,那就会改变eat中的其中一个bit位

    哈希切割

    例:给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法,这里就要用到哈希切割

    注意:如果Ai和Bi都太大,可以考虑换个哈希函数,再切割一次 

    全部代码

  • 相关阅读:
    自然之州阿肯色及温泉国家公园
    如果你是一个 Java 面试官,你会问哪些问题?
    怎样才能让百度搜索到自己的博客?--九五小庞
    Mybatis SQL构建器
    jdk1.8中list按对象的某个属性分组
    每日练习------随机产生一个1-100之间的整数,看能几次猜中。要求:猜的次数不能超过7次,每次猜完之后都要提示“大了”或者“小了”。
    云端炼丹,算力白嫖,基于云端GPU(Colab)使用So-vits库制作AI特朗普演唱《国际歌》
    原码,反码,补码以及计算
    Flutter布局组件:水平/垂直组件、叠加布局组件、流式布局组件
    取证之查看本机保存的WiFi密码
  • 原文地址:https://blog.csdn.net/weixin_58867976/article/details/125464703