哈希表---开链法解决哈希冲突
上篇文章已经写过构造哈希表时用开放定址法解决哈希冲突,这次我就来写写这个开链法解决哈希冲突的问题!
一、结点定义
我们已经知道开链法大概是一种什么结构了,(如果不知道,这里有讲哦点我点我)显而易见,实现哈希桶的话我们就必须多一个指针next,至少这样才看起来有个链表的样子嘛!!
- //开链法(哈希桶)
- template<class K,class V>
- struct KVNode
- {
- K _key;
- V _value;
- KVNode<K,V>* _next;
- KVNode(const K& key,const V& value)
- :_key(key)
- ,_value(value)
- ,_next(NULL)
- {}
- };
二、哈希表的实现----Inser、Find、Remove
以数组int a[] = {51, 105, 52, 3, 55, 2, 106, 53, 0}为例
Insert:
老规矩,我们还是得判断这个key在表中是否存在,如果存在就插入失败;当两个key有相同的散列地址时,我们只需将前一个结点的next指针指向新结点即可!那么,我们在同一个散列地上的链表进行插入结点时,用头插好还是尾插好呢?!当然是头插好了,这样我们就不用每次遍历到链表的尾结点,这可省了不少事儿!!
以上面这个数组为例,假设51和105分别都已经插入在正确的位置(此时表长53),接下来需要插入52,我们利用头插进行插入
如果表中的某个位置此时为NULL,当要进行插入时,做法与上述一样。
- bool Insert(const K& key,const V& value)
- {
- if (Find(key)) //已经存在这个数
- return false;
- _CheckSize();
- size_t index = _HashFunc(key,_table.size());
- Node* tmp = new Node(key,value);
- tmp->_next = _table[index];
- _table[index] = tmp;
- _size++;
- return true;
- }
Find:
首先要找到key的散列地址,再在这个地址上挂着的链表开始遍历查找,直到找到相同的key为止。
- Node* Find(const K& key)
- {
- if (_size == 0)
- return NULL;
- size_t index = _HashFunc(key,_table.size());
- Node* cur = _table[index];
- while (cur)
- {
- if (cur->_key == key)
- return cur;
- cur = cur->_next;
- }
- //没有找到
- return false;
- }
Delete:
删除一个数据时就是要删除这个结点,删除结点的方式与删除链表一个结点的方式是一样的,只要改变前一个结点的next指针。不过在这之前我们需要通过散列地址找到这个结点。假如要删除53表示的这个结点
- bool Remove(const K& key)
- {
- if(_size == 0)
- return false;
- size_t index = _HashFunc(key,_table.size());
- Node* cur = _table[index];
- Node* prev = NULL;
- while (cur)
- {
- while(cur->_key == key)
- {
- //删除的是头(第一个)结点
- if (prev == NULL)
- {
- _table[index] = cur->_next;
- }
- //删除非头结点(中间或后边)
- else
- {
- prev->_next = cur->_next;
- }
- delete cur;
- _size--;
- return true;
- }
- prev = cur;
- cur = cur->_next;
- }
- return false;
- }
具体代码:
- //开链法(哈希桶)
- template<class K,class V>
- struct KVNode
- {
- K _key;
- V _value;
- KVNode<K,V>* _next;
- KVNode(const K& key,const V& value)
- :_key(key)
- ,_value(value)
- ,_next(NULL)
- {}
- };
- template<class K,class V>
- class HashTable
- {
- typedef KVNode<K,V> Node;
- public:
- HashTable()
- :_size(0)
- {
- _table.resize(3);
- }
- ~HashTable()
- {
- for (size_t i=0; i<_table.size(); ++i)
- {
- Node* cur = _table[i];
- while (cur)
- {
- Node* tmp = cur->_next;
- delete cur;
- cur = tmp;
- }
- _size = 0;
- _table.clear();
- }
- }
- Node* Find(const K& key);
- bool Remove(const K& key);
- bool Insert(const K& key,const V& value);
- void Display()
- {
- for (size_t i=0; i<_table.size(); ++i)
- {
- printf("Table[%d]->",i);
- Node* cur = _table[i];
- while (cur)
- {
- Node* next = cur->_next;
- cout<<cur->_key<<" ";
- cur = next;
- }
- cout<<NULL;
- cout<<endl;
- }
- }
- protected:
- void _CheckSize()
- {
- if (_table.size() == 0 || _size == _table.size())
- {
- vector<Node*> tmpTable;
- tmpTable.resize(_GetPrimer(_table.size()));
- //将原表_table中的结点直接放入新表中
- for (size_t i=0; i<_table.size(); ++i)
- {
- Node* cur = _table[i];
- while (cur)
- {
- Node* next = cur->_next;
- size_t index = _HashFunc(cur->_key,tmpTable.size());
- cur->_next = tmpTable[index];
- tmpTable[index] = cur;
- cur = next;
- }
- }
- _table.swap(tmpTable);
- }
- }
- size_t _GetPrimer(size_t size)
- {
- const int _PrimeSize = 28;
- static const unsigned long _PrimeList[_PrimeSize] =
- {
- 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<_PrimeSize; ++i)
- {
- if (_PrimeList[i] > size)
- {
- return _PrimeList[i];
- }
- }
- }
- size_t _HashFunc(const K& key,size_t size)
- {
- return key%size;
- }
- protected:
- vector<Node*> _table;
- size_t _size; //已有的数据个数
- };
哈希表---开链法解决哈希冲突相关推荐
- 06 数据结构与算法之哈希表(拉链法) (C语言实现)
注:只给出C语言实现代码,涉及到的数据结构相关概念请自行阅读相关书籍或参考其他博文: 将哈希表理解为一个顺序表,顺序表里面存储的是一个链表(拉链法解决碰撞) 注:(hash & 0x7FFFF ...
- 拉链法解决哈希冲突的方式和几种常见的散列函数
本文探讨拉链表解决哈希冲突的方式和几种常见的散列函数. 首先,什么是散列表? 对于一个数组,我们在O(1)时间复杂度完成可以完成其索引的查找,现在我们想要存储一个key value的键值对,我们可以根 ...
- C++哈希表最详细解决
目录 1 哈希表理论基础 1. 1 哈希函数 1.2 哈希碰撞 2 哈希表力扣题参考代码 原文链接 代码随想录 1 哈希表理论基础 首先什么是 哈希表,哈希表(英文名字为Hash table,国内也 ...
- 什么是哈希表?什么又是哈希冲突?哈希冲突的解决方法?
首先,什么是哈希表?什么又是哈希冲突? ①哈希表是基于数组的一种存储方式.它主要由哈希函数和数组构成.当要存储一个数据的时候,首先用一个函数计算数据的地址,然后再将数据存进指定地址位置的数组里面.这个 ...
- 趣谈哈希表优化:从规避 Hash 冲突到利⽤ Hash 冲突
导读:本文从哈希表传统设计与解决思路入手,深入浅出地引出新的设计思路:从尽量规避哈希冲突,转向了利⽤合适的哈希冲突概率来优化计算和存储效率.新的哈希表设计表明 SIMD 指令的并⾏化处理能⼒的有效应⽤ ...
- 【哈希表】(一) 设计哈希表
目录 一.设计哈希表 二.设计哈希表的关键 三.设计哈希集合 3.1 题目要求 3.2 解决过程 四.设计哈希映射 4.1 题目要求 4.2 解决过程 五.设计哈希表 - 解决方案 六.复杂度分析 - ...
- C++ 哈希表查询_进入哈希函数结界的世界
1. 前言 哈希表或称为散列表,是一种常见的.使用频率非常高的数据存储方案. 哈希表属于抽象数据结构,需要开发者按哈希表数据结构的存储要求进行 API 定制,对于大部分高级语言而言,都会提供已经实现好 ...
- 哈希表题目:设计哈希映射
文章目录 题目 标题和出处 难度 题目描述 要求 示例 数据范围 前言 解法一 思路和算法 代码 复杂度分析 解法二 思路和算法 代码 复杂度分析 题目 标题和出处 标题:设计哈希映射 出处:706. ...
- 在java中 哈希表会经常出现哈希碰撞吗
在Java中,哈希表可能会经常出现哈希碰撞.哈希表是一种根据键(Key)来访问值(Value)的数据结构,通过哈希函数将键映射到哈希表的索引位置上.由于哈希函数的映射结果可能不唯一,不同的键可能会被映 ...
- 哈希表-拉链法及应用举例
哈希表存储结构: 1.开放寻址法 2.拉链法 哈希表的主要作用: 把一个较大(0-10^9 )的数据映射到较小(0-N(N一般为10^5 到 10^6))的数据 哈希函数:可以把一个从-10^19 到 ...
最新文章
- SDUT_2122 数据结构实验之链表七:单链表中重复元素的删除
- 【深入Java虚拟机】之四:类加载机制
- Firefox火狐浏览器自用技巧汇总--以备使用--13.5.16
- 当前最好的非深度迁移学习方法:流形空间下的分布对齐
- WebKit 分析–for android【new】
- 字符串相似度匹配算法python_算法字符串相似度得分/哈希
- ResourceBundle国际化
- Qt设计器中,使用QToolBar控件的技巧
- 计费软件 0day 被用于攻陷美国某工程公司,8个未修复0day再现
- Linux 命令(54)—— trap 命令(builtin)
- Vue项目webpack打包部署到Tomcat,刷新报404错
- PAT乙级做题部分总结
- 【3D目标检测】点云数据 To 360度全景图
- 用友U9sv服务打开时报错内存入口检查失败,因为可用内存(371662848 字节)少于总内存的 5%
- 小米路由器刷Xiaomi Mi WiFi Mini openwrt
- 我的一点企业上云经验
- 2018哈理工院个人赛、校团队赛总结
- 【calendar日历组件】elementul的日历组件点击拿到对应的日期或者触发某些事件
- 赛扬处理器_Intel低功耗奔腾/赛扬“变砖”:紧急退市、升级
- win7 mysql 卸载不干净,win7系统彻底删除mysql的方法教程
热门文章
- 仿照LFW的pair.txt生成自己数据集的txt文件
- Burp Suite使用介绍说明
- 物联网工程导论笔记一:RFID及二维码技术
- 非线性系统线性化过程
- Android四大组件之广播
- p系列服务器产品介绍,常用p系列服务器RS6000服务器产品号码对照表.doc
- MYSQL 触发器 实践案例
- 无线路由器网络测试软件,如何简单快速测试家里无线路由器的网速和性能?
- Awesomium(一)-- WebSnapshot
- bodymovin导出没有html5,AE导出Web动画插件Bodymovin 5.7.6+使用教程 For CC 2014 – CC 2020...