Hash 哈希(上)

简介

Hash,又称散列,它通过对数据进行计算,得出该数据的对应位置,使得数据和存放位置相对应,从而完成高效的查找。


Hash函数的构造

取余法

用关键字\(k\)除以\(M\),取余数作为地址。

\[\operatorname h(k)=k \bmod M
\]

经验上\(P\)可以为\(k\)的取值可能数的1~2倍范围内的素数或\(k\)的取值可能数本身。

这类函数主要用于整数。

乘积取整法

用关键字\(k\)乘一个在\((0,1)\)中的实数\(A\)(最好是无理数),取其小数部分,乘\(M\)并取整,作为地址。

\[\operatorname h(k)=\left\lfloor{M(kA\bmod1)}\right\rfloor
\]

经验上\(A\)可以为\(\dfrac{\sqrt{5}-1}{2}\)。

这类函数主要用于小数。

其他方法

  • 自身函数:取\(k\)的某个线性函数值作为地址。
\[\operatorname h(k)=a\times k+b
\]
  • 平方取中法:将\(k\)平方后取中间几位作为地址。
  • 折叠法:将\(k\)分成位数相等的几段,但最后一段可以不同,最后相加作为地址。

冲突的处理

大部分的散列表无法避免冲突(废话) 。因此需要一些数据结构来解决这些冲突。

挂链法

顾名思义,当出现冲突时,用链表将这两个关键字连起来。看看代码有点像向量存图:

const int array_size=1e5+5;//数组大小
vector<int>lis[array_size];
void get_hash(int key)//加入一个值为key的元素
{
int buc=f(key);
lis[buc].push_back(key);
}
bool check(int key)//查找一个元素是否存在于Hash表中
{ int buc=f(key);
for(int i=0;i<lis[buc].size();i++)
if(lis[buc][i]==key)
return true;
return false;
}

在键值均匀分布的前提下,挂链法操作的时间复杂度为\(O(n\texttt{length}(\texttt{Hash table}))\)。

开放定址法

这种方法将所有元素直接存于散列表中,因此散列表大小不能小于元素个数。开放定址法中有一个特殊的函数\(H(x,k)\),指明如果前\(k\)次访问失败,下一次应访问哪一个位置。这个函数有三种构造方式:

线性探查法

\[\operatorname H(x,k)=(x+1)\bmod \text {array_size}
\]

二次探查法

\[\operatorname H(x,k)=(x+k^2)\bmod \text{array_size}
\]

双哈希法

这种方法需要引入一个新的\(Hash\)函数\(newh(x)\):

\[\operatorname H(x,k)=(x,k\times newh(x))\bmod\text{array_size}
\]

其中线性探查法有最优的缓存访问与计算消耗,二次探查法次之,双哈希法最劣。不过双哈希法的概率相等,能够避免“聚集”,即大量\(Hash\)值接近的情况。

三种方法代码类似:

const int array_size=1e5+5;//数组大小
int val[array_size];
int H(int buc,int opercnt){…}//上文提到的函数
void get_hash(int key)//加入元素操作
{
int buc=f(key,array_size);
while(val[buc]!=key&&val[buc])
buc=(buc==array_size-1?0:buc+1);
val[buc]=key;
}
bool check(int key)//查询元素操作
{
int buc=f(key,array_size),opercnt=0;
while(val[buc]!=key&&val[buc])
buc=H(buc,opercnt++);
return val[buc]==key;
}

在键值均匀分布的前提下,开放定址法时间复杂度为\(O(\texttt{length(Hash table)/(length(Hash table)}-n))\)

结语

以上是一些Hash的常用方法,限于篇幅这里仅提到了数值的哈希。

Hash还有更多的骚操作应用,如字符串哈希,排列哈希,树或图的哈希,Hash哈希(下)会提到的(光速逃

\[\xrightarrow{\qquad}To\;be\;continued\cdots
\]

Hash 哈希(上)的更多相关文章

  1. 上传图片用图片文件的对象hash哈希值判断图片是否一样,避免重复提交相同的图片到服务器中

    上传图片用图片文件的对象hash哈希值判断图片是否一样,避免重复提交相同的图片到服务器中 前端:要用到一个插件,点击下载 <!DOCTYPE html> <html xmlns=&q ...

  2. hash 哈希查找复杂度为什么这么低?

    hash 哈希查找复杂度为什么这么低? (2017-06-23 21:20:36) 转载▼   分类: c from: 作者:jillzhang 出处:http://jillzhang.cnblogs ...

  3. Hash哈希(一)

    Hash哈希(一) 哈希是大家比较常见一个词语,在编程中也经常用到,但是大多数人都是知其然而不知其所以然,再加上这几天想写一个一致性哈希算法,突然想想对哈希也不是很清楚,所以,抽点时间总结下Hash知 ...

  4. redis:hash哈希类型的操作

    1. hash哈希类型的操作 1.1. hset key field value 语法:hset key field value 作用:把key中field域的值设为value 注:如果没有field ...

  5. 第二百九十六节,python操作redis缓存-Hash哈希类型,可以理解为字典类型

    第二百九十六节,python操作redis缓存-Hash哈希类型,可以理解为字典类型 Hash操作,redis中Hash在内存中的存储格式如下图: hset(name, key, value)name ...

  6. Hash哈希(二)一致性Hash(C++实现)

    一致性Hash 一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,经常用于分布式.负载均衡等. 原理 一致哈希是 ...

  7. Hash(哈希)

    一.基本概念 Hash,一般翻译做"散列",也有直接音译为"哈希"的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的 ...

  8. Redis[三] @Hash 哈希

    Redis的哈希值是字符串字段和字符串值之间的映射,所以他们是表示对象的完美数据类型 在Redis中的哈希值,可存储超过400十亿键值对. redis 提供了2套操纵 一种是批量 一种是非批量 假设需 ...

  9. python hash 哈希值

    自增知识点 1,哈希 什么是可哈希(hashable)? 简要的说可哈希的数据类型,即不可变的数据结构(字符串str.元组tuple.对象集objects). 哈希有啥作用? 它是一个将大体量数据转化 ...

随机推荐

  1. Python练习题 015:一颗自由落地的球

    [Python练习题 015] 一球从100米高度自由落下,每次落地后反跳回原高度的一半,再落下.求它在第10次落地时,共经过多少米?第10次反弹多高? ----------------------- ...

  2. SQL实战——04. 查找所有已经分配部门的员工的last_name和first_name以及dept_no (一个逗号引发的血案)

    查找所有已经分配部门的员工的last_name和first_name以及dept_noCREATE TABLE `dept_emp` (`emp_no` int(11) NOT NULL,`dept_ ...

  3. 最全vue的vue-amap使用高德地图插件画多边形范围

    一.在vue-cli的框架下的main.js(或者main.ts)中引入高德插件,代码如下: import Vue from 'vue' import VueAMap from 'vue-amap' ...

  4. Java中的对象都是在堆上分配的吗?

    作者:LittleMagic https://www.jianshu.com/p/8377e09971b8 为了防止歧义,可以换个说法: Java对象实例和数组元素都是在堆上分配内存的吗? 答:不一定 ...

  5. Thinkphp中D方法和M方法的区别

    两者共同点都是实例化模型的,而两者不同点呢?一起来看一下: $User = D('User');括号中的参数User,对应的模型类文件的 \Home\Model\UserModel.class.php ...

  6. 用 Java 实现的八种常用排序算法

    八种排序算法可以按照如图分类 交换排序 所谓交换,就是序列中任意两个元素进行比较,根据比较结果来交换各自在序列中的位置,以此达到排序的目的. 1. 冒泡排序 冒泡排序是一种简单的交换排序算法,以升序排 ...

  7. 8.Android-简单的登录案例编写

    本章来学习登录案例,由于还未学习自定义控件外观,所以ui界面先用最简单的,并保存登录账号密码到data/data/包名/files下 1.学习之前需要掌握的Context类(通过Context来往AP ...

  8. 迎难而上,QPS提高22+倍

    简介 记录1次性能提升的经历,它最大的挑战不在于性能提升,而在于时间急,涉及的面广(比如:机房F5的SSL/TLS性能,机房互联网流量费和项目投入产出比等).性能指标:至少支持10K QPS,10ms ...

  9. 用python和GDAL 读取GRIB数据

    from osgeo import gdal import numpy as np path = './data/201912/anl_surf125.2019120100' dataset = gd ...

  10. 远程Jenkins新增Mac电脑节点

    一,前言 上一篇博客Jenkins集成appium自动化测试(Windows篇)介绍了怎么使用远程Jenkins新建节点连接本地Windows电脑进行Appium自动化测试集成. 但是在做ios Ap ...