首页 > 哈希--直接定值法和除留取余法

哈希--直接定值法和除留取余法

1. 哈希是一种算法,哈希表是用哈希算法构造出来的一种数据结构
2. 哈希算方法的几种方法
  • 直接定值法
这里有一个例题,就是我们想判断某一字符串中,某一个字符出现的个数,我们可以使用哈希的思想,就是可以遍历一遍字符串,然后开辟一个拥有26数据的整型数组,然后初始化全部为0,然后统计利用一种映射的思想,遍历字符串的时候,就把相应的位置++,每次我们查找某一个字符的时候,一下子就可以定值到那个字符的位置
还有一个例子就是,比如让我们存储1-10这个区间的不重复的数据,这个时候我么也是开辟一个拥有十个元素的整型数组,然后每个数据对应给位置,这样我们在查找的时候,就可以直接查找到这个数据是否存在。
第三个例子是,这里有一些 数据,比如是1001,1006,1009,1007这个时候我们知道数据的范围,我们也是可以开辟一个存储空间来存放这个数据,只不过这个时候我们不需要开辟1000多个大小的数组,我么只需要开辟十个即可,上面的每个数据都减去1000,然后在存放在这个位置,然后我们读取的时候也是按照这个规则读取
分析:上面的几种都是特殊的简单的情况,太具有局限性,还有就是如果我们的数据跨度很大的话,要开辟很大的存储空间,这显然是不合适的,但是一种解题的思路
  • 除留取余法
这里有一部分数据然后我们不能开辟所有的大小的空间,这个时候我呢就出现了一个除留取余法,我们的可以把数据都取余数组的长度,然后放置在相应的位置上面去。
致命缺点:哈希冲突,即是我们的数据可能映射的位置是同一个位置
法一:闭散列法--开放地址法
(1)第一种方式是线性探测
其他的发生冲突的数据直接往后面走,直到有一个位置上面的数据为空,这个时候把数据放置上去。
比如我么的数据,有89,18,49,58,9,我们开辟的整型数组的空间空间时十个,然后我们放置89,89%10 = 9,然后把89放置在了第九个位置上面去,接着是放置18,18被放置在了8这个位置上面。然后拿到49的时候,我们的数据9这个位置已经后数据,这个时候,我们依次往后走,知道扎到了0号位置是空的,于是49被放置在了0这个位置上面去了。同样 的方法放置其他的数据。
数据放置好了之后,就是查找数据了,这个是时候,如果找9,首先定位到9这个位置上面上,然后没有找到,然后就是依次往后面找,知道找到9,或者就是找到一个空位置停止,这个时候 是没有找到相关的数据。
但是这种方式留下了一个问题就是,如果我们冲突的数据都是集中在了9这个位置了,那每次查找的时候是不是很麻烦,这个时候我我们采用的方法及时二次探测。
(2)第二种方式是二次探测
二次探测的方式值这样的,89进来的时候还是直接放置数据,但是当49进来的时候,不是直接往后面放置了,而是往后移动1的平方个位置,如果是空的就是直接放置,如果不是空的,就是相对于起始位置移动2的 平方个,依次类推下去,直到有一个位置为空。
第一个问题:我们既然已经知道了一次探测的冲突比较大,所以我们这里直接采用的是二次探测
第二个问题:我们的考虑使用数组,但是因为后面的数据可能会增加的很大,所以我们还会考虑增容的操作,这个时候我们不妨直接使用vector。
第三个问题:我们一开始的时候,初始化的时候,初始值应该是多少呢,大家可能和自然的想到了是0,但是有一个问题就是,但是如果我要找的数据就是0的,那不是GG了,所以我们在设计类的成员变量的时候的时候,vector里面的内容 可以放置的是一个结构体,结构体的一部分是数据,一部分是标识位,标识我们的这个位置上面有没有数据
第四个问题:我们既然有增加数据,就一定有删除数据,那个如果是上面的例子,我现在删除了一个数据是49,然后我接下来可能是要找9,这个时候首先定位到下标为9的这个位置,然后往后面二次探测1的平方,这个时候找到了49这个 位置,发现是空,就不往下找了,显然这是不符合 我们的要求的,于是我们想设计结构体的时候,这个标识位有三个值,一个标识有数据,一个标识没有数据,一个标识删除数据,于是我们想到了枚举类型。
第五个问题:我们需要考虑的什么时候增容呢,一开始的想法是当vector满了之后再增容 ,可是这种增容的话,当我们的vector满的 时候是不是数据的冲突就可能大呢,于是我们想的是当已经 放置的数据个数的大小时vector的容量大小的0.7的时候开始增容。
第六个问题:我们的数据在放入的时候,可能在二次探测的时候,可能会出现一只循环在写某些位置,这个 问题下一讲在解决。


代码:hashtable.h

#include
using namespace std;
#include//作为一个标记位
enum State   
{EMPTY,EXIT,DEL
};//哈希节点
template
struct HashNode
{pair _kv;State _state;HashNode():_state(EMPTY){}
};template
ostream& operator<<(ostream &out, HashNode node)
{out << " "<< " " << node._state;return out;
}template
class HashTable
{//friend ostream& operator<<(ostream &out, HashNode node);
public:HashTable():_n(0){_table.resize(10);  //预留的数租空间大小是}//插入函数bool Insert(const pair node){Capacity();int m = HanshFunc(node);  //HanshFunc,找到我需要插入的一个下标size_t index = m;size_t i = 0;while (_table[index]._state == EXIT){index = m;i++;index = m + i*i;while (index >= _table.capacity()){index = index - _table.capacity();}}_table[index]._kv = node;_table[index]._state = EXIT;_n++;return true;}int Search(const pair node){size_t m = HanshFunc(node);size_t index = m;size_t i = 0;while (_table[index]._kv.first != node.first){if (_table[index]._state == EMPTY){return -1;}index = m;i++;index = m + i*i;while (index >= _table.capacity()){index = index - _table.capacity();}}return index;}private:void Capacity(){//if (_n / _table.capacity() >= 0.7)   //这类需要改进的一个地方 就是,我们不能使用0.7,因为除以了之后,不是一个小数//{//	printf("增容
");//}if (_n * 10 / _table.capacity() >= 7){printf("增容
");}}int HanshFunc(const pair node){size_t index = node.first % _table.capacity();return index;}private:vector> _table;  //这个是数组size_t _n;  //当前放置的数据的个数是多少
};




HashTable.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include"hashtable.h"int main()
{HashTable a;pair p(5,6);pair p1(15,7);pair p2(25, 6);pair p3(85, 6);pair p4(75, 6);pair p5(95, 6);pair p6(2, 6);pair p7(4, 6);a.Insert(p);a.Insert(p1);a.Insert(p2);a.Insert(p3);a.Insert(p4);a.Insert(p5);a.Insert(p6);a.Insert(p7);cout << a.Search(p);return 0;
}




更多相关:

  • 本文是西门子开放式TCP通信的第2篇,上一篇我们讲了使用西门子1200PLC作为TCP服务器的程序编写,可以点击下方链接阅读:【公众号dotNet工控上位机:thinger_swj】基于Socket访问西门子PLC系列教程(一)在完成上述步骤后,接下来就是编写上位机软件与PLC之间进行通信。上位机UI界面设计如下图所示:从上图可以看出...

  • 我有一个大型数据集,列出了在全国不同地区销售的竞争对手产品。我希望通过使用这些新数据帧名称中的列值的迭代过程,根据区域将该数据帧分成几个其他区域,以便我可以分别处理每个数据帧-例如根据价格对每个地区的信息进行排序,以了解每个地区的市场情况。我给出了以下数据的简化版本:Competitor Region ProductA Product...

  • 作为一名IT从业者,我来回答一下这个问题。首先,对于具有Java编程基础的人来说,学习Python的初期并不会遇到太大的障碍,但是要结合自己的发展规划来制定学习规划,尤其要重视学习方向的选择。Java与Python都是比较典型的全场景编程语言,相比于Java语言来说,当前Python语言在大数据、人工智能领域的应用更为广泛一些,而且大...

  • 这段时间通过学习相关的知识,最大的变化就是看待事物更加喜欢去了解事物后面的本质,碰到问题后解决问题思路也发生了改变。举个具体的例子,我在学习数据分析,将来会考虑从事这方面的工作,需要掌握的相关专业知识这个问题暂且按下不表,那哪些具体的问题是我需要了解的呢,以下简单罗列:1、了解数据分析师这个岗位在各个地区的需求情况?2、数据分析师的薪...

  • 这一节将开始学习python的一个核心数据分析支持库---pandas,它是python数据分析实践与实战的必备高级工具。对于使用 Python 进行数据分析来说,pandas 几乎是无人不知,无人不晓的。今天,我们就来认识认识数据分析界鼎鼎大名的 pandas。目录一. pandas主要数据结构 SeriesDataFrame二...

  • 英语的重要性,毋庸置疑!尤其对广大职场人士,掌握英语意味着就多了一项竞争的技能。那,对于我们成人来说,时间是最宝贵的。如何短时间内在英语方面有所突破,这是我们最关心的事情。英语学习,到底有没有捷径可以走,是否可以速成?周老师在这里明确告诉大家,英语学习,没有绝对的捷径走,但是可以少走弯路。十多年的教学经验告诉我们,成功的学习方法可以借...

  • 展开全部 其实IDLE提供了一个显32313133353236313431303231363533e78988e69d8331333365663438示所有行和所有字符的功能。 我们打开IDLE shell或者IDLE编辑器,可以看到左下角有个Ln和Col,事实上,Ln是当前光标所在行,Col是当前光标所在列。 我们如果想得到文件代码...

  • 前言[1]从 Main 方法说起[2]走进 Tomcat 内部[3]总结[4]《Java 2019 超神之路》《Dubbo 实现原理与源码解析 —— 精品合集》《Spring 实现原理与源码解析 —— 精品合集》《MyBatis 实现原理与源码解析 —— 精品合集》《Spring MVC 实现原理与源码解析 —— 精品合集》《Spri...

  • 【本文摘要】【注】本文所述内容为学习Yjango《学习观》相关视频之后的总结,观点归Yjango所有,本文仅作为学习之用。阅读本节,会让你对英语这类运动类知识的学习豁然开朗,你会知道英语学习方面,我们的症结所在。学习英语这类运动类知识,需要把握四个原则第一,不要用主动意识。第二,关注于端对端第三,输入输出符合实际情况第四,通过多个例子...

  • 点云PCL免费知识星球,点云论文速读。文章:RGB-D SLAM with Structural Regularities作者:Yanyan Li , Raza Yunus , Nikolas Brasch , Nassir Navab and Federico Tombari编译:点云PCL代码:https://github.co...

  • 给定一个非负整数数组,你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个位置。 示例 1: 输入: [2,3,1,1,4] 输出: true 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 示例 2:...