hash 算法

对于判重,我们能想到的方法有什么??

①bool数组

②set(集)

数组与集合的优缺点:

1.因为集合是对数组做的封装,所以,数组永远比任何一个集合要快。

2.数组声明了它容纳的元素的类型,而集合不声明。这是由于集合以object形式来存储它们的元素。

3.一个数组实例具有固定的大小,不能伸缩。集合则可根据需要动态改变大小。

4.数组是一种可读/可写数据结构---没有办法创建一个只读数组。

③map(映射)  

④hash    

因为数组,set,map的适用范围是比较小的,而且速度很慢,所以今天我们就来研究一下hash!!!

哈希算法

* 回忆八数码问题:判重,给定一个九位数,怎么判断有没有在前面出现过?

* 考虑一种压缩数组的方法:如果我们想要把数组大小变为 N,那么对于一个数 X,存储在 X%N 的位置里面。

* 这样可以完美解决空间问题。

 

 哈希算法 - 冲突

* 但存在一种情况:两个数 X 计算到了同一个位置(X%N = Y%N)

模数的确定:  取比元素个数大的质数
* 该如何解决?

 

 

* 第一种解决方式:顺序寻址法
* 一直往后查询位置,直到有空为止。

哈希算法 - 判断

* 如何判断这个数是否在之前已经出现过了?

* 类比插入过程,一直往后查询位置,直到出现两种情况之一。
-1 有空位:那就没出现过
-2 查询到一个相等的数:说明已经出现过了

哈希算法 - 顺序寻址法 - 代码实现

int hash_table[N]; // hash_table 哈希表:0 位置代表没有数
void push1(int x)
{
    int y = x % N; // 计算初始位置,N:表的大小
    for(; hash_table[y] && hash_table[y]!=x; ) y = (y+1) % N;
    // 寻找到一个 0 位置,或者找到自己为止
    if(hash_table[y]) cout << x << "␣has␣occured␣before!" << endl;
    // 如果是自己本身,则之前已经出现过了
    else
    {
        hash_table[y] = x; // 否则,将 x 加入表中
        cout << x << "␣inserted." << endl;
    }
}

哈希算法 - 冲突 - 解决的另一种方式
* 但存在一种情况:两个数 X 计算到了同一个位置(X%N = Y%N)
* 另一种解决方案:把所有数堆到一起(也就是用链表将模数相同的都连起来)

 

哈希算法 - 链地址法 - 代码实现

// 方法二:链地址法
vector<int> hash_array[N]; // hash_array:每个位置用一个 vector 来维护
void push2(int x) {
  int y = x % N; // 计算初始位置
  for(int i=0; i<hash_array[y].size(); i++)
  if(hash_array[y][i] == x) // 如果之前已经出现过了
  {
    cout << x << "␣has␣occured␣before!" << endl;
    return; // 标记已经出现过
  }
  // 如果之前没有出现过,将 x 加入表中
  hash_array[y].push_back(x);
  cout << x << "␣inserted." << endl;
}

字符串哈希

* 十进制表示法——我需要计算出所有前缀所代表的数字。

 

 上图,在S[5]存的是39618,S[4]存的是3961,S[3]存的是396,S[2]存的是96,S[1]存的是6

* 假如需要计算区间 [l,r]所代表的数字 X,有
    X = S[r] − S[l − 1] × 10r−l+1

字符串哈希 - 联系

* 数字和字符串有什么联系吗?我们可以把一个字符串看作是一个特殊的数字:

* 对于字符串“ABABC”,我们定义它的哈希值 H 为:H = ”A” ∗ D^4 + ”B” ∗ D^3 + ”A” ∗ D^2 + ”B” ∗ D + ”C”

- 其中 D 为一个规定的数。

D在字符串全为大写或者全为小写时,范围是26~27,当字符串中既有大写又有小写时,取52

* 那么我们可以把字符串看作是一个D 进制的数。计算方法和数字是类似的,而且对于相同字符串,得到的结果是相同的。

字符串算法 - 代码实现

string s; // s 为字符串
int f[N], g[N]; // f 为前缀和,g[i] 为 D 的 i 次方
void prehash(int n) // 预处理哈希值
{
  // 预处理时,注意到数字可能很大,对一个数 MD 取模
  f[0] = 0; // f 前缀和预处理
  for(int i=1; i<=n; i++) f[i] = (1LL * f[i-1] * D + s[i-1]) % MD;
  g[0] = 1; // g:D 次方预处理
  for(int i=1; i<=n; i++) g[i] = 1LL * g[i-1] * D % MD;
}
int hash(int l, int r) // 计算区间 [l,r] 的哈希值
{
  int a = f[r];
  int b = 1LL * f[l-1] * g[r-l+1] % MD; // 记得乘上次方
  return (a - b + MD) % MD; // 前缀和相减
// 有可能结果小于 0,加上一个 MD 将其变为正数
}
if(hash(a, b) == hash(c, d)) // 字符串 [a,b] 与字符串 [c,d] 匹配

字符串算法 - 几点注意事项

* 哈希算法:数组长度 N 用质数,减少冲突的次数,增加效率

* 字符串哈希:因为只是用一个小于 MD 的数来代表一个字符串,也是一种哈希;所以有可能会产生冲突(不同的字符串有相同的数),

- 可以通过前面的方法来解决:设哈希表(但速度很慢)。
- 解决方式:用质数来减少冲突的可能性;用几组不同的 D 与 MD

// 哈希算法: N 使用质数
const int N = 1000003;
// 字符串哈希: 多用质数,不容易产生冲突
const int D = 131; const int MD = 1e9 + 7;
// 用几组不同的 D 与 MD
const int D2 = 31; const int MD2 = 1e9 + 9;

 

自己选的路,跪着也要走完!!!

 

转载于:https://www.cnblogs.com/wsdestdq/p/6831041.html

<think>嗯,用户问的是关于哈希算法的问题。我需要先解释哈希算法是什么,以及它在Python中的应用。首先,哈希算法的作用是将任意长度的数据转换成固定长度的哈希值,这个值通常用来快速查找、数据完整性校验等。常见的应用场景比如哈希表、加密、校验文件等。 接下来,我得列举常见的哈希算法,比如MD5、SHA系列,还有Python中的内置hash()函数。需要提到它们的区别,比如MD5虽然快但不够安全,SHA-256更安全但速度慢一些。另外,Python的hash()函数可能在不同环境下有不同的表现,比如在64位和32位系统上结果不同,或者因为哈希随机化导致不同进程的结果不同。 然后,我需要给出Python中使用这些算法代码示例。比如用hashlib库实现MD5、SHA-256,以及如何用hash()函数处理不可变类型。还要注意,可变类型如列表不能直接哈希,但元组可以。所以可能需要转换类型后再使用hash()。 另外,可能需要提到哈希算法的特性,比如确定性、抗碰撞性、雪崩效应等。这些是哈希算法设计的重要原则,确保其安全性和有效性。 在问题解决方面,用户可能遇到哈希冲突的问题,这时候需要解决方法,比如链地址法或开放寻址法。或者在使用哈希函数时需要注意安全性,避免使用不安全的算法如MD5存储密码,应该用bcrypt或PBKDF2等。 最后,相关的问题应该围绕哈希算法的应用场景、解决冲突的方法、安全性和Python中的具体实现。确保问题覆盖用户可能进一步询问的方向。</think><< 哈希算法Hash Algorithm)是一种将任意长度的输入数据转换为固定长度输出的算法。输出的结果称为哈希值(Hash Value)或摘要(Digest)。哈希算法具有以下核心特性: 1. **确定性**:相同输入始终产生相同哈希值。 2. **高效性**:计算速度快。 3. **抗碰撞性**:不同输入极难生成相同哈希值。 4. **不可逆性**:无法从哈希值反推原始输入。 ### Python中的哈希算法实现 Python通过标准库`hashlib`提供了多种哈希算法。以下是常见算法代码示例: #### 1. MD5(不推荐用于安全场景) ```python import hashlib data = "Hello, World!".encode('utf-8') md5_hash = hashlib.md5(data).hexdigest() print(md5_hash) # 输出: 65a8e27d8879283831b664bd8b7f0ad4 ``` #### 2. SHA-256(安全哈希算法) ```python sha256_hash = hashlib.sha256(data).hexdigest() print(sha256_hash) # 输出: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f ``` #### 3. Python内置`hash()`函数 ```python # 仅适用于不可变对象(如整数、字符串、元组) print(hash("Python")) # 输出: 539294692(Python 3.11+可能启用随机哈希种子) ``` ### 哈希算法应用场景 1. **数据完整性验证**(如文件校验) 2. **密码存储**(需结合盐值) 3. **哈希表数据结构**(字典实现基础) 4. **数字签名** ### 注意事项 - **碰撞风险**:MD5/SHA-1已知存在碰撞漏洞 - **哈希长度**:SHA-256输出256位,SHA-512输出512位 - **加盐处理**:存储密码时应使用`hashlib.pbkdf2_hmac` ### 哈希冲突示例 ```python # 不同输入可能产生相同哈希值(概率极低但存在) collision1 = hash("a") # 不同Python版本结果可能不同 collision2 = hash("b") print(collision1 == collision2) # 可能输出False,但理论上存在True的情况 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值