• 波奇学C++:哈希


    哈希本质是的值和位置建立关联起来,这种关联关系就是哈希函数

    示例:除留余数:对输入的数字取模。

    哈希冲突:多个不同的值指向同一个位置

    解决方法:

    闭散列:开发地址法。

    把24放在下一个位置

    哈希桶

    闭散列法

    闭散列的负载因子:表元素个数/散列表长度(size),当负载因子达到一定范围时就进行扩容。

    扩容会涉及重新映射,取模的范围变大了。

    闭散列的元素搜索:闭散列的元素搜索到空截止,要搜索的值只可能往后延,不可能提前,所以如果为空,说明没有。

    闭散列的删除:不能直接置空,而是要设置一个状态值表示是否删除。

    1. enum STATE
    2. {
    3. EXIST,
    4. EMPTY,
    5. DELETE
    6. };

    对于其他类型string,可以选择仿函数来取哈希值,算法上的难点是取哈希值的方式。

    其中一个算法

    1. template<>
    2. struct DefaultHashFunc
    3. {
    4. size_t operator()(const string& str)
    5. {
    6. // BKDR
    7. size_t hash = 0;
    8. for (auto ch : str)
    9. {
    10. hash *= 131;
    11. hash += ch;
    12. }
    13. return hash;
    14. }
    15. };

    完整代码

    1. namespace myhashtable {
    2. enum STATE
    3. {
    4. EXIST,
    5. EMPTY,
    6. DELETE
    7. };
    8. template<class K, class V>
    9. struct HashData
    10. {
    11. pair _kv;
    12. STATE _state = EMPTY;
    13. };
    14. template<class K>
    15. struct DefaultHashFunc
    16. {
    17. size_t operator()(const K& key)
    18. {
    19. return (size_t)key;
    20. }
    21. };
    22. template<>
    23. struct DefaultHashFunc
    24. {
    25. size_t operator()(const string& str)
    26. {
    27. // BKDR
    28. size_t hash = 0;
    29. for (auto ch : str)
    30. {
    31. hash *= 131;
    32. hash += ch;
    33. }
    34. return hash;
    35. }
    36. };
    37. template<class K, class V,class HashFunc=DefaultHashFunc>
    38. class HashTable
    39. {
    40. public:
    41. HashTable()
    42. {
    43. _table.resize(10);
    44. }
    45. bool Insert(const pair& kv)
    46. {
    47. //扩容
    48. if ((double)_n * 10 / (double)_table.size() >= 0.7)
    49. {
    50. size_t newSize = _table.size() * 2;
    51. // 扩容以后映射关系变了
    52. HashTable newHT;
    53. newHT._table.resize(newSize);
    54. // 遍历旧表的数据插入新表就可以了
    55. for (size_t i = 0; i < _table.size(); i++)
    56. {
    57. if (_table[i]._state == EXIST)
    58. {
    59. newHT.Insert(_table[i]._kv);
    60. }
    61. }
    62. _table.swap(newHT._table);
    63. }
    64. HashFunc hf;
    65. size_t hashi =hf( kv.first) % _table.size();
    66. while (_table[hashi]._state == EXIST)
    67. {
    68. ++hashi;
    69. hashi %= _table.size();
    70. }
    71. _table[hashi]._kv = kv;
    72. _table[hashi]._state = EXIST;
    73. ++_n;
    74. return true;
    75. }
    76. HashData<const K, V>* Find(const K& key)
    77. {
    78. HashFunc hf;
    79. size_t hashi = hf(key) % _table.size();
    80. while (_table[hashi]._state != EMPTY)
    81. {
    82. if (_table[hashi]._state == EXIST
    83. && _table[hashi]._kv.first == key)
    84. {
    85. return (HashData<const K, V>*) & _table[hashi]._kv;
    86. }
    87. ++hashi;
    88. hashi %= _table.size();
    89. }
    90. return nullptr;
    91. }
    92. bool Erase(const K& key)
    93. {
    94. HashData<const K, V>* ret = Find(key);
    95. if (ret)
    96. {
    97. ret->_state = DELETE;
    98. --_n;
    99. return true;
    100. }
    101. return false;
    102. }
    103. private:
    104. vector> _table;
    105. size_t _n =0;
    106. };
    107. }

    哈希桶方法

    关键点:哈希表存节点地址,用单链表存冲突的哈希值

    1. namespace bush_bucket
    2. {
    3. template<class K,class V>
    4. struct HashNode
    5. {
    6. pair _kv;
    7. HashNode* _next;
    8. HashNode(const pair kv)
    9. {
    10. _kv = kv;
    11. _next = nullptr;
    12. }
    13. };
    14. template<class K,class V>
    15. class HashTable
    16. {
    17. typedef HashNode Node;
    18. public:
    19. HashTable()
    20. {
    21. _table.resize(10,nullptr);
    22. }
    23. ~HashTable()
    24. {
    25. for (size_t i= 0; i < _table.size(); i++)
    26. {
    27. Node* cur = _table[i];
    28. while (cur)
    29. {
    30. Node* next = cur->_next;
    31. delete cur;
    32. cur = next;
    33. }
    34. _table[i] = nullptr;
    35. }
    36. }
    37. bool Insert(const pair& kv)
    38. {
    39. if (Find(kv.first))
    40. {
    41. return false;
    42. }
    43. // 扩容
    44. if (_n == _table.size())
    45. {
    46. size_t newSize = _table.size()*2;
    47. vector newTable;
    48. newTable.resize(newSize, nullptr);
    49. for (size_t i = 0; i < _table.size(); i++)
    50. {
    51. Node* cur = _table[i];
    52. while (cur)
    53. {
    54. Node* next = cur->_next;
    55. size_t hashi = cur->_kv.first % newSize;
    56. cur->_next = newTable[hashi];
    57. newTable[hashi] = cur;
    58. cur = next;
    59. }
    60. _table[i] = nullptr;
    61. }
    62. _table.swap(newTable);
    63. }
    64. size_t hashi = kv.first % _table.size();
    65. Node* newnode = new Node(kv);
    66. newnode->_next = _table[hashi];
    67. _table[hashi] = newnode;
    68. ++_n;
    69. return true;
    70. }
    71. Node* Find(const K& key)
    72. {
    73. size_t hashi = key% _table.size();
    74. Node* cur = _table[hashi];
    75. while (cur)
    76. {
    77. if (cur->_kv.first == key)
    78. {
    79. return cur;
    80. }
    81. cur = cur->_next;
    82. }
    83. return nullptr;
    84. }
    85. bool Erase(const K& key)
    86. {
    87. size_t hashi = key % _table.size();
    88. Node* prev = nullptr;
    89. Node* cur = _table[hashi];
    90. while (cur)
    91. {
    92. if (cur->_kv.first == key)
    93. {
    94. if (prev == nullptr)
    95. {
    96. _table[hashi] = cur->_next;
    97. }
    98. else
    99. {
    100. prev->_next = cur->_next;
    101. }
    102. delete cur;
    103. return true;
    104. }
    105. prev = cur;
    106. cur = cur->_next;
    107. }
    108. return false;
    109. }
    110. void Print()
    111. {
    112. for (int i = 0; i < _table.size(); i++)
    113. {
    114. printf("[%d]->", i);
    115. Node* cur = _table[i];
    116. while (cur)
    117. {
    118. cout << cur->_kv.first << "->";
    119. cur = cur->_next;
    120. }
    121. printf("null");
    122. printf("\n");
    123. }
    124. }
    125. private:
    126. vector _table; //指针数组
    127. size_t _n=0;
    128. };
    129. }

  • 相关阅读:
    解决:执行virtuoso&命令打开cadence很慢,很卡
    __main__文件学习测试如下
    sublime快捷键!+tab键失效
    计算机三级备考——数据库技术
    mysql 基于GTID方式的bin-log日志恢复数据
    工时管理:警惕员工时间偷窃!企业应该如何避免?
    Pycharm 自定义文件和代码模板
    基于 Bitbucket 的 CI/CD 在 Flutter 中的应用
    数据结构--希尔排序
    jsoncpp库的使用及用httplib库搭建HTTP服务器
  • 原文地址:https://blog.csdn.net/Bagayalu1234567/article/details/133694197