哈希学习笔记

本文详细阐述了哈希的概念,包括哈希函数的作用、原理(如字符串哈希和取模运算),以及哈希表的构造和操作(插入、查询的时间复杂度)。通过实例展示了如何用C++实现哈希和哈希表,重点讨论了空间和时间效率优化。
摘要由CSDN通过智能技术生成

1. 哈希

1.1. 功能

存在性判断,判断是否相等

1.2. 原理

1.2.1. 哈希函数

把大范围的一组数 A i A_i Ai映射到 B i B_i Bi
每个 A i A_i Ai有且只有一个对应的 B i B_i Bi
一个 B i B_i Bi可能对应多个 A i A_i Ai(哈希碰撞)
常用哈希函数:
f ( x ) = x f(x)=x f(x)=x
f ( x ) = a b s ( x )   m o d   M f(x)=abs(x) \bmod M f(x)=abs(x)modM
f ( x ) = ( x   m o d   M + M )   m o d   M f(x)=(x \bmod M +M) \bmod M f(x)=(xmodM+M)modM
f ( x ) = x & M f(x)=x \& M f(x)=x&M,其中M=0xfffff

1.2.1.1. 字符串哈希
1.2.1.1.1. 功能:

将字符串 S S S映射到整数 B B B
通过判断B是否相等,判断S是否相等

1.2.1.1.2. 原理

把字符串的每项看做数位,
每个字符对应一个数字,
则字符串可以看作一个 P P P进制的数。
字符串哈希值 = ∑ i = 0 l e n ( S ) − 1 S i × P i =\sum_{i=0}^{len(S)-1}S_i \times P^i =i=0len(S)1Si×Pi

P=10
s="abccd"
h=12334

为了存入int64_t,每次运算需要取余数。
或使用uint64_t,自动取模于 2 64 2^{64} 264(自然溢出)。
为减少哈希冲突, P , M P,M P,M通常为质数,常用
P 1 = 131 , P 2 = 137 , M 1 = 1 0 9 + 7 , M 2 = 1 0 9 + 9 P_1=131,P_2=137,M_1=10^9+7,M_2=10^9+9 P1=131,P2=137,M1=109+7,M2=109+9
也可同时用多组 P , M P,M P,M(双哈希)
取模后,若 哈希 ( S 1 ) = 哈希 ( S 2 ) 哈希(S_1)=哈希(S_2) 哈希(S1)=哈希(S2)
则极大概率有 S 1 = S 2 S_1=S_2 S1=S2

若要获取子串哈希值,可使用前缀和。
涉及字符串反转后相等(如回文串问题),
同时使用前缀和、后缀和。

P=10,s="abccd"
h[1]=1
h[2]=12
h[3]=123
h[4]=1233
h[5]=12334
s(3~4)="cc"
h(3~4)=1233-12*10**2=33
h(i~j)=h[j]-h[i-1]*P**(j-i+1)
1.2.1.1.3. 实现
const int64_t P=131,M=1e9+7;

获取字符串哈希

int64_t strHash(const std::string s){
    int64_t h=0;
    for(int i=0;i<s.size();i++){
        h=(h*P%M+(s[i]-'a'+1))%M;
    }
    return h;
}

前缀和实现 O ( 1 ) O(1) O(1)获取子串哈希

std::string s;//下标从1开始
int n;//s的长度
int64_t h[N]/*前缀和数组*/int64_t p[N]/*P的i次方*/;
//N为字符串长度
void init(){
    p[0]=1;
    for(int i=1;i<=n;i++){
        h[i]=(h[i-1]*P%M+(s[i]-'a'+1))%M;
        p[i]=p[i-1]*P%M;
    }
}
int64_t subHash(int l,int r){
    return ((h[r]-h[l-1]*p[r-l+1]%M)%M+M)%M;
}

1.2.2. 哈希表

为避免哈希碰撞导致错误判断,
A i A_i Ai存入 M + 1 M+1 M+1个线性表(常用链表)中,
B i B_i Bi做线性表组的下标(哈希函数需要保证 B i < M B_i<M Bi<M

M=10,f(x)=x%10,x>0
h0
100
h1
1
201
31
h2
2
22
72
h3
13
h4
14
44
... ...
h9
9

空间复杂度: O ( M + l e n ( A ) ) O(M+len(A)) O(M+len(A))

1.3. 操作

1.3.1. 插入元素

h[f(x)].insert(x)

时间复杂度取决于线性表的插入时间复杂度
若用链表实现则为 O ( 1 ) O(1) O(1)
若用std::vecter实现则近似 O ( 1 ) O(1) O(1),实际大于 O ( 1 ) O(1) O(1)

1.3.2. 查询元素

h[f(x)].find(x)

h[f(x)]中有 k k k个元素,
则时间复杂度为 O ( k ) O(k) O(k)
近似为 O ( 1 ) O(1) O(1)

1.4. 实现

#define K 0x3fffff
struct S{
    int64_t v;
    int nxt;
};
S h[(int)1e7];//len(B)
int e=1;//结尾标记,0表示nullptr,不存数据
int hd[K+1];
bool find(int64_t x){
    for(int i=hd[x&K];i;i=h[i].nxt){
        if(h[i].v==x)return 1;
    }
    return 0;
}
void insert(int64_t x){
    if(find(x))return;
    h[e]=S{x,hd[x&K]};
    hd[x&K]=e++;
}
  • 21
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
哈希图像检索是一种用于在大规模图像数据库中快速搜索相似图像的方法。在哈希图像检索中,图像被转换为哈希码,然后通过比较哈希码的相似性来确定图像之间的相似度。有几种常用的哈希算法可以用于图像检索,如SIFT、SURF、ORB等特征提取算法\[1\]。此外,还有一些基于哈希的图像检索方法,如VLAD、BOF等,可以用于处理海量数据的图像检索\[1\]。 在哈希图像检索中,可以使用不同的方法来计算图像之间的相似度。一种常用的方法是通过比较图像的颜色、纹理和局部特征来计算相似度\[2\]。另外,还可以使用KD-Tree、局部敏感哈希(LSH)和原子哈希函数等方法来在高维空间中进行图像检索\[2\]。 此外,还有一种基于监督学习和核的Hash算法,称为KSH算法。KSH算法利用核主要是为了解决线性不可分问题,通过监督学习学习到更有区分度的哈希值,从而降低特征维数\[3\]。 总之,哈希图像检索是一种用于在大规模图像数据库中快速搜索相似图像的方法,它可以通过提取图像特征和计算相似度来实现。不同的哈希算法和方法可以用于不同的图像检索任务。 #### 引用[.reference_title] - *1* *3* [图像检索传统算法学习笔记](https://blog.csdn.net/qq_39858278/article/details/83895342)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [8月23日计算机视觉理论学习笔记——图像检索](https://blog.csdn.net/Ashen_0nee/article/details/126467437)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值