Hash,一般翻译做散列、杂凑,或音译为哈希。————摘自百度百科

先来看个题:给你一坨一些键值集<key,value>,\(key\)的范围是\([1,10^{10}]\),每次询问\(x\),回答\(key=x\)的\(value\)这种一看就知道暴力不行……于是,有些同学会说:我会用map!但map的查询是 \(O(logn)\)的 QwQ。那么哈希可以怎么做呢?我们可以让\(hash[f(key)]=value\),其中\(f()\)函数被称为哈希函数。至于\(f()\)函数怎么写……想怎么写就怎么写!没错,你想怎么写就怎么写。一般有这么几种方法:

  1. 直接定值法:让\(F(key)=key\)。读者:那不和一般的一样嘛!要你何用?咳咳,总要从最基础的开始嘛……好了,这个方法就此结束。
  2. 折叠法:将关键字分成几部分,取这几部分的和的前几位为哈希地址。例如ISBN码(对就是那道入门题),以0-442-20586-4为例,可以得到其哈希地址是:\(hash = 0442 + 2058 + 64 = 2564\)诶?之前不是说前几位吗?因为这里没有进位啊……如果得到结果是\(10934\),那么其哈希地址就是\(0934\)。
  3. 取余数法:这是\(OI\)中最最常用的,就是对其求余为哈希地址,如\(4325\),模\(233333\)后得\(4325\),那么她的哈希地址就是\(4325\)。

那么现在上面那个问题就好解决了,只要用取余数法求得\(key\)的哈希地址就可以大大压缩空间了!

但是,你不要高兴太早!相信有许多人已经看出来了,哈希的缺点很明显,就是容易出现不同的元素有同一个哈希地址的情况,我们一般称其为:哈希冲突。那么有什么方法能解决哈希冲突呢?有许多方法:

  1. 线性探测再散列:如果多个数有同一个哈希地址,如:0 0 0 34 6 44 0 0注:0表示没有元素。然后又有一个元素\(8\),得到其哈希地址也是4(即34所在的位置),那么我们就往后挪一挪:大哥你先来的,我到后面去。于是来到了6的位置——也被占了,那么再往后移……最后到了7(即44后面那个)。然后查询时只要依次往后找就可以了。
  2. 多重哈希:个人比较喜欢叫双模数,就是进行多次哈希,当然,每次的模数都不一样。如果两次哈希的地址都对应,我才认为是同一个。一般情况下双模数就足够了,所以我喜欢叫双模数。要是有三模数,那基本不会冲突了。
  3. 链地址法:还记得链式前向星吗?(不记得!那还不滚回去学)链式前向星就是把其后面一个一个地链起来,这个也一样,如果哈希地址相同,就链起来。于是乎,我们又想:那开个\(vector\)岂不是又方便又可以解决哈希冲突?没错,我也喜欢用\(vector\)。这两种你用哪一种都没关系,不过还是先提醒一下:\(vector\)有可能会爆哦!这也是为什么大家用链式前向星而不用\(vector\)的原因!(所以我也要开始习惯用链地址法了)。
  4. 建立一个公共溢出区:这个方法我不会!(不会还理直气壮……)所以这里不讲,而且这个方法最后得到的模数不是一个质数,而且其因数很多,是2的次幂,所以……出题人卡你是很容易的!

解决哈希冲突的方法一般就是这些啦!还有个问题,上面提到模数要是质数,为什么呢?原因很简单,根据质数的特性,质数每一个位置都能很好的利用起来,而合数不可以。而且这个质数要大一点(废话,你来个19,玩个鬼哦)。

好,讲完了基础的,来看一看例题:

P3370 【模板】字符串哈希

噫,刚刚只说了整数哈希啊!没关系,记得ASCII码吗?我们可以通过ASCII码,将其转成一个\(base\)进制数,当然,是模过的。然后再用链地址法,对同一哈希值的字符串进行遍历,如果都不相同,加入并更新答案。

具体代码实现:

#include<cstdio>
#include<string>
#include<vector>
#include<iostream>
#define mod 23333
#define base 298
#define rg register
using namespace std;
int n,ans;
string s;
vector<string>v[mod+5];
void insert()
{
int hash=1;//记录哈希值,由于后面要乘所以初值是1
for(rg int i=0;i<s.length();i++)
hash=(1ll*hash*base+s[i])%mod;//1ll就是(long long)1,乘一个1ll,可以保证不爆精度(当然你爆long long或高精度我也没办法)
string t=s;//暂存一下
for(rg int i=0;i<v[hash].size();i++)
if(v[hash][i]==t) return ;//判断,如果有相同的就退出
v[hash].push_back(t);//加入新的字符串
ans++;//更新答案
return ;
}
int main()
{
scanf("%d",&n);
for(rg int i=1;i<=n;i++)
{
cin>>s;
insert();
}
printf("%d",ans);
return 0;
}

哦对了,一般233333(2后面跟一堆3)、100007(1和7中间隔一堆0)、1000009(1和9中间隔一堆0)都是质数。

就讲这么多吧,之后就要靠大家自己实现了!重点还是在多刷题啊!

哈希,hash的更多相关文章

  1. redis 哈希(hash)函数

    哈希(hash)函数 hSet 命令/方法/函数 Adds a value to the hash stored at key. If this value is already in the has ...

  2. redist命令操作(二)--哈希Hash,列表List

    1.Redis 哈希(Hash) 参考菜鸟教程:http://www.runoob.com/redis/redis-hashes.html Redis hash 是一个string类型的field和v ...

  3. Redis中的哈希(Hash)

    Redis 哈希(Hash) Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象. Redis 中每个 hash 可以存储 232 - 1 键值 ...

  4. NSDictionary实现原理-ios哈希hash和isEqual

    NSDictionary实现原理-ios哈希hash和isEqual   OC中自定义类的NSCopying实现的注意事项(isEqual & hash实现) http://blog.csdn ...

  5. 大话Java中的哈希(hash)结构(一)

    o( ̄▽ ̄)d 小伙伴们在上网或者搞程序设计的时候,总是会听到关于“哈希(hash)”的一些东西.比如哈希算法.哈希表等等的名词,那么什么是hash呢? 一.相关概念 1.hash算法:一类特殊的算法 ...

  6. Python操作redis系列以 哈希(Hash)命令详解(四)

    # -*- coding: utf-8 -*- import redis #这个redis不能用,请根据自己的需要修改 r =redis.Redis(host=") 1. Hset 命令用于 ...

  7. Redis 命令,键(key),字符串(String),哈希(Hash),列表(List),集合(Set)(二)

      Redis 命令 Redis 命令用于在 redis 服务上执行操作. 要在 redis 服务上执行命令需要一个 redis 客户端.Redis 客户端在我们之前下载的的 redis 的安装包中. ...

  8. 哈希--Hash,“散列”/“哈希”

    哈希 Hash,翻译“散列”,音译为“哈希”,把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值.这种转换是一种压缩映射,也就是散列值的空间通常远小于输入的空间,不同的输入可能会散 ...

  9. 区块链 - 哈希(Hash)

    章节 区块链 – 介绍 区块链 – 发展历史 区块链 – 比特币 区块链 – 应用发展阶段 区块链 – 非对称加密 区块链 – 哈希(Hash) 区块链 – 挖矿 区块链 – 链接区块 区块链 – 工 ...

  10. redis(八):Redis 哈希(Hash)

    Redis 哈希(Hash) Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象. Redis 中每个 hash 可以存储 232 ...

随机推荐

  1. 前端面试基础题:Ajax原理

    Ajax 的原理简单来说是在⽤户和服务器之间加了—个中间层( AJAX 引擎),通过XmlHttpRequest 对象来向服务器发异步请求,从服务器获得数据,然后⽤ javascrip t 来操作 D ...

  2. Qt实现的多菜单选择界面

    文章目录 1.效果展示 2.实现代码 2.1 菜单实现代码 2.1.1 头文件 2.1.2 源文件 2.2 应用代码 1.效果展示 这种菜单样式比较常用,实现的方法也有很多种,比如可以直接使用QTab ...

  3. Meow 攻击会删除不安全(开放的)的Elasticsearch(及MongoDB) 索引,然后建一堆以Meow结尾的奇奇怪怪的索引(如:m3egspncll-meow)

    07月29日,早上照例一来,先连接Elasticsearch查看日志[禁止转载,by @CoderBaby],结果,咦,什么情况,相关索引被删除了,产生了一堆以Meow开头的奇奇怪怪的索引,如下图: ...

  4. docker安装gitlab并部署CICD

    摘要 本文主要实现了在docker下安装gitlab,将gitlab绑定在宿主机的180端口,将gitlab的clone的URL添加指定端口号:部署了CI/CD,并公布了测试项目. 安装docker[ ...

  5. JAVA多线程之生产者 消费者模式 妈妈做面包案例

    创建四个类 1.面包类 锅里只可以放10个面包 ---装面包的容器2.厨房 kitchen 生产面包 和消费面包  最多生产100个面包3.生产者4消费者5.测试类 多线程经典案例 import ja ...

  6. C#LeetCode刷题之#15-三数之和(3Sum)

    目录 问题 示例 分析 问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3618 访问. 给定一个包含 n 个整数的 ...

  7. vue 公众号H5 使用微信JSAPI 录音 完整齐全

    官方文档必须首当其冲 1.微信jsAPI 录音文档 2.获取微信临时素材文档 首先H5录音功能的话 对于普通H5网上是有很多的方法 插件  但是兼容性很差 特别是对于ios 一开始想的是用H5 做个通 ...

  8. 靶机练习 - ATT&CK红队实战靶场 - 1. 环境搭建和漏洞利用

    最近某个公众号介绍了网上的一套环境,这个环境是多个Windows靶机组成的,涉及到内网渗透,正好Windows和内网渗透一直没怎么接触过,所以拿来学习下. 下载地址:http://vulnstack. ...

  9. jQuery的基础效果题

    Jquery第二次考核 之真金不怕火炼 1.  名词解释 实例对象:var p1=new Person();  p1就是实例对象 构造:function Person(){} 原型对象:在 JavaS ...

  10. Linux学习笔记 一 第二章 Linux系统安装

    Linux系统安装 一.首先安装VMware 虚拟机 下载网址:https://www.vmware.com/cn/products/workstation-pro/workstation-pro-e ...