上篇文章已经写过构造哈希表时用开放定址法解决哈希冲突,这次我就来写写这个开链法解决哈希冲突的问题!

一、结点定义

我们已经知道开链法大概是一种什么结构了,(如果不知道,这里有讲哦点我点我)显而易见,实现哈希桶的话我们就必须多一个指针next,至少这样才看起来有个链表的样子嘛!!

[cpp] view plaincopy
  1. //开链法(哈希桶)
  2. template<class K,class V>
  3. struct KVNode
  4. {
  5. K _key;
  6. V _value;
  7. KVNode<K,V>* _next;
  8. KVNode(const K& key,const V& value)
  9. :_key(key)
  10. ,_value(value)
  11. ,_next(NULL)
  12. {}
  13. };

二、哈希表的实现----Inser、Find、Remove

以数组int a[] = {51, 105, 52, 3, 55, 2, 106, 53, 0}为例

Insert:

老规矩,我们还是得判断这个key在表中是否存在,如果存在就插入失败;当两个key有相同的散列地址时,我们只需将前一个结点的next指针指向新结点即可!那么,我们在同一个散列地上的链表进行插入结点时,用头插好还是尾插好呢?!当然是头插好了,这样我们就不用每次遍历到链表的尾结点,这可省了不少事儿!!

以上面这个数组为例,假设51和105分别都已经插入在正确的位置(此时表长53),接下来需要插入52,我们利用头插进行插入

如果表中的某个位置此时为NULL,当要进行插入时,做法与上述一样。

[cpp] view plaincopy
  1. bool Insert(const K& key,const V& value)
  2. {
  3. if (Find(key))  //已经存在这个数
  4. return false;
  5. _CheckSize();
  6. size_t index = _HashFunc(key,_table.size());
  7. Node* tmp = new Node(key,value);
  8. tmp->_next = _table[index];
  9. _table[index] = tmp;
  10. _size++;
  11. return true;
  12. }

Find:

首先要找到key的散列地址,再在这个地址上挂着的链表开始遍历查找,直到找到相同的key为止。

[cpp] view plaincopy
  1. Node* Find(const K& key)
  2. {
  3. if (_size == 0)
  4. return NULL;
  5. size_t index = _HashFunc(key,_table.size());
  6. Node* cur = _table[index];
  7. while (cur)
  8. {
  9. if (cur->_key == key)
  10. return cur;
  11. cur = cur->_next;
  12. }
  13. //没有找到
  14. return false;
  15. }

Delete:

删除一个数据时就是要删除这个结点,删除结点的方式与删除链表一个结点的方式是一样的,只要改变前一个结点的next指针。不过在这之前我们需要通过散列地址找到这个结点。假如要删除53表示的这个结点

[cpp] view plaincopy
  1. bool Remove(const K& key)
  2. {
  3. if(_size == 0)
  4. return false;
  5. size_t index = _HashFunc(key,_table.size());
  6. Node* cur = _table[index];
  7. Node* prev = NULL;
  8. while (cur)
  9. {
  10. while(cur->_key == key)
  11. {
  12. //删除的是头(第一个)结点
  13. if (prev == NULL)
  14. {
  15. _table[index] = cur->_next;
  16. }
  17. //删除非头结点(中间或后边)
  18. else
  19. {
  20. prev->_next = cur->_next;
  21. }
  22. delete cur;
  23. _size--;
  24. return true;
  25. }
  26. prev = cur;
  27. cur = cur->_next;
  28. }
  29. return false;
  30. }

具体代码:

[cpp] view plaincopy
  1. //开链法(哈希桶)
  2. template<class K,class V>
  3. struct KVNode
  4. {
  5. K _key;
  6. V _value;
  7. KVNode<K,V>* _next;
  8. KVNode(const K& key,const V& value)
  9. :_key(key)
  10. ,_value(value)
  11. ,_next(NULL)
  12. {}
  13. };
  14. template<class K,class V>
  15. class HashTable
  16. {
  17. typedef KVNode<K,V> Node;
  18. public:
  19. HashTable()
  20. :_size(0)
  21. {
  22. _table.resize(3);
  23. }
  24. ~HashTable()
  25. {
  26. for (size_t i=0; i<_table.size(); ++i)
  27. {
  28. Node* cur = _table[i];
  29. while (cur)
  30. {
  31. Node* tmp = cur->_next;
  32. delete cur;
  33. cur = tmp;
  34. }
  35. _size = 0;
  36. _table.clear();
  37. }
  38. }
  39. Node* Find(const K& key);
  40. bool Remove(const K& key);
  41. bool Insert(const K& key,const V& value);
  42. void Display()
  43. {
  44. for (size_t i=0; i<_table.size(); ++i)
  45. {
  46. printf("Table[%d]->",i);
  47. Node* cur = _table[i];
  48. while (cur)
  49. {
  50. Node* next = cur->_next;
  51. cout<<cur->_key<<" ";
  52. cur = next;
  53. }
  54. cout<<NULL;
  55. cout<<endl;
  56. }
  57. }
  58. protected:
  59. void _CheckSize()
  60. {
  61. if (_table.size() == 0 || _size == _table.size())
  62. {
  63. vector<Node*> tmpTable;
  64. tmpTable.resize(_GetPrimer(_table.size()));
  65. //将原表_table中的结点直接放入新表中
  66. for (size_t i=0; i<_table.size(); ++i)
  67. {
  68. Node* cur = _table[i];
  69. while (cur)
  70. {
  71. Node* next = cur->_next;
  72. size_t index = _HashFunc(cur->_key,tmpTable.size());
  73. cur->_next = tmpTable[index];
  74. tmpTable[index] = cur;
  75. cur = next;
  76. }
  77. }
  78. _table.swap(tmpTable);
  79. }
  80. }
  81. size_t _GetPrimer(size_t size)
  82. {
  83. const int _PrimeSize = 28;
  84. static const unsigned long _PrimeList[_PrimeSize] =
  85. {
  86. 53ul, 97ul, 193ul, 389ul, 769ul,
  87. 1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
  88. 49157ul, 98317ul, 196613ul, 393241ul,
  89. 786433ul,
  90. 1572869ul, 3145739ul, 6291469ul, 12582917ul,
  91. 25165843ul,
  92. 50331653ul, 100663319ul, 201326611ul, 402653189ul,
  93. 805306457ul,
  94. 1610612741ul, 3221225473ul, 4294967291ul
  95. };
  96. for (size_t i=0; i<_PrimeSize; ++i)
  97. {
  98. if (_PrimeList[i] > size)
  99. {
  100. return _PrimeList[i];
  101. }
  102. }
  103. }
  104. size_t _HashFunc(const K& key,size_t size)
  105. {
  106. return key%size;
  107. }
  108. protected:
  109. vector<Node*> _table;
  110. size_t _size;   //已有的数据个数
  111. };

哈希表---开链法解决哈希冲突相关推荐

  1. 06 数据结构与算法之哈希表(拉链法) (C语言实现)

    注:只给出C语言实现代码,涉及到的数据结构相关概念请自行阅读相关书籍或参考其他博文: 将哈希表理解为一个顺序表,顺序表里面存储的是一个链表(拉链法解决碰撞) 注:(hash & 0x7FFFF ...

  2. 拉链法解决哈希冲突的方式和几种常见的散列函数

    本文探讨拉链表解决哈希冲突的方式和几种常见的散列函数. 首先,什么是散列表? 对于一个数组,我们在O(1)时间复杂度完成可以完成其索引的查找,现在我们想要存储一个key value的键值对,我们可以根 ...

  3. C++哈希表最详细解决

    目录 1 哈希表理论基础 1. 1 哈希函数 1.2 哈希碰撞 2 哈希表力扣题参考代码 原文链接  代码随想录 1 哈希表理论基础 首先什么是 哈希表,哈希表(英文名字为Hash table,国内也 ...

  4. 什么是哈希表?什么又是哈希冲突?哈希冲突的解决方法?

    首先,什么是哈希表?什么又是哈希冲突? ①哈希表是基于数组的一种存储方式.它主要由哈希函数和数组构成.当要存储一个数据的时候,首先用一个函数计算数据的地址,然后再将数据存进指定地址位置的数组里面.这个 ...

  5. 趣谈哈希表优化:从规避 Hash 冲突到利⽤ Hash 冲突

    导读:本文从哈希表传统设计与解决思路入手,深入浅出地引出新的设计思路:从尽量规避哈希冲突,转向了利⽤合适的哈希冲突概率来优化计算和存储效率.新的哈希表设计表明 SIMD 指令的并⾏化处理能⼒的有效应⽤ ...

  6. 【哈希表】(一) 设计哈希表

    目录 一.设计哈希表 二.设计哈希表的关键 三.设计哈希集合 3.1 题目要求 3.2 解决过程 四.设计哈希映射 4.1 题目要求 4.2 解决过程 五.设计哈希表 - 解决方案 六.复杂度分析 - ...

  7. C++ 哈希表查询_进入哈希函数结界的世界

    1. 前言 哈希表或称为散列表,是一种常见的.使用频率非常高的数据存储方案. 哈希表属于抽象数据结构,需要开发者按哈希表数据结构的存储要求进行 API 定制,对于大部分高级语言而言,都会提供已经实现好 ...

  8. 哈希表题目:设计哈希映射

    文章目录 题目 标题和出处 难度 题目描述 要求 示例 数据范围 前言 解法一 思路和算法 代码 复杂度分析 解法二 思路和算法 代码 复杂度分析 题目 标题和出处 标题:设计哈希映射 出处:706. ...

  9. 在java中 哈希表会经常出现哈希碰撞吗

    在Java中,哈希表可能会经常出现哈希碰撞.哈希表是一种根据键(Key)来访问值(Value)的数据结构,通过哈希函数将键映射到哈希表的索引位置上.由于哈希函数的映射结果可能不唯一,不同的键可能会被映 ...

  10. 哈希表-拉链法及应用举例

    哈希表存储结构: 1.开放寻址法 2.拉链法 哈希表的主要作用: 把一个较大(0-10^9 )的数据映射到较小(0-N(N一般为10^5 到 10^6))的数据 哈希函数:可以把一个从-10^19 到 ...

最新文章

  1. SDUT_2122 数据结构实验之链表七:单链表中重复元素的删除
  2. 【深入Java虚拟机】之四:类加载机制
  3. Firefox火狐浏览器自用技巧汇总--以备使用--13.5.16
  4. 当前最好的非深度迁移学习方法:流形空间下的分布对齐
  5. WebKit 分析–for android【new】
  6. 字符串相似度匹配算法python_算法字符串相似度得分/哈希
  7. ResourceBundle国际化
  8. Qt设计器中,使用QToolBar控件的技巧
  9. 计费软件 0day 被用于攻陷美国某工程公司,8个未修复0day再现
  10. Linux 命令(54)—— trap 命令(builtin)
  11. Vue项目webpack打包部署到Tomcat,刷新报404错
  12. PAT乙级做题部分总结
  13. 【3D目标检测】点云数据 To 360度全景图
  14. 用友U9sv服务打开时报错内存入口检查失败,因为可用内存(371662848 字节)少于总内存的 5%
  15. 小米路由器刷Xiaomi Mi WiFi Mini openwrt
  16. 我的一点企业上云经验
  17. 2018哈理工院个人赛、校团队赛总结
  18. 【calendar日历组件】elementul的日历组件点击拿到对应的日期或者触发某些事件
  19. 赛扬处理器_Intel低功耗奔腾/赛扬“变砖”:紧急退市、升级
  20. win7 mysql 卸载不干净,win7系统彻底删除mysql的方法教程

热门文章

  1. 仿照LFW的pair.txt生成自己数据集的txt文件
  2. Burp Suite使用介绍说明
  3. 物联网工程导论笔记一:RFID及二维码技术
  4. 非线性系统线性化过程
  5. Android四大组件之广播
  6. p系列服务器产品介绍,常用p系列服务器RS6000服务器产品号码对照表.doc
  7. MYSQL 触发器 实践案例
  8. 无线路由器网络测试软件,如何简单快速测试家里无线路由器的网速和性能?
  9. Awesomium(一)-- WebSnapshot
  10. bodymovin导出没有html5,AE导出Web动画插件Bodymovin 5.7.6+使用教程 For CC 2014 – CC 2020...