This commit is contained in:
Zengtudor 2024-10-24 13:04:48 +08:00
parent 3638a0c290
commit 83782debf5

View File

@ -1686,7 +1686,160 @@ int main() {
# 哈希表
## 数值哈希函数构造
在C++中计算数值哈希可以通过多种方法实现,下面是一种常见的方法,使用标准库中的哈希函数来计算数值的哈希值。
### 示例代码
```cpp
#include <iostream>
#include <functional>
int main() {
int number = 12345; // 要计算哈希值的数
std::hash<int> hash_fn; // 创建哈希函数对象
size_t hash_value = hash_fn(number); // 计算哈希值
std::cout << "Number: " << number << std::endl;
std::cout << "Hash Value: " << hash_value << std::endl;
return 0;
}
```
### 说明
1. **`<functional>` 头文件**: 该头文件提供了哈希函数的定义。
2. **`std::hash<int>`**: 这是一个用于计算整数的哈希值的模板类。你可以用它来计算不同类型的哈希值,比如 `std::hash<float>``std::hash<double>` 等。
3. **哈希值计算**: 调用 `hash_fn(number)` 来获取 `number` 的哈希值。
### 注意事项
- 哈希函数并不保证唯一性:不同的输入可能会产生相同的哈希值(称为哈希冲突)。
- 使用自定义的哈希函数:如果需要更复杂的哈希逻辑,可以创建自己的哈希函数。
### 自定义哈希函数示例
如果你想实现一个自定义的哈希函数,可以如下操作:
```cpp
#include <iostream>
size_t custom_hash(int number) {
return static_cast<size_t>(number) * 2654435761 % (1 << 30); // 乘以一个质数
}
int main() {
int number = 12345;
size_t hash_value = custom_hash(number);
std::cout << "Number: " << number << std::endl;
std::cout << "Custom Hash Value: " << hash_value << std::endl;
return 0;
}
```
### 总结
以上方法提供了一种计算数值哈希的简单方式。可以根据实际需求选择标准库的哈希函数或自定义哈希函数。
## 字符串哈希函数构造
使用 C++ 字符串哈希函数的构造通常涉及以下几个步骤。我们会利用哈希算法将字符串映射到一个整数值,从而实现快速的字符串比较和查找。以下是一个简单的字符串哈希函数的实现及其原理。
### 哈希函数构造
#### 1. 选择基数和模数
- **基数 (base)**: 通常选择一个质数,常见的有 31、53 等。
- **模数 (mod)**: 一个大质数,防止哈希冲突。
#### 2. 哈希计算
对于字符串中的每个字符 \( s[i] \),我们可以用以下公式计算哈希值:
\[
hash(s) = (s[0] \times base^0 + s[1] \times base^1 + s[2] \times base^2 + \ldots + s[n-1] \times base^{n-1}) \mod mod
\]
其中 \( n \) 是字符串的长度。
### C++ 示例代码
以下是一个简单的 C++ 实现:
```cpp
#include <iostream>
#include <string>
class StringHash {
public:
// 构造函数
StringHash(const std::string& str) {
base = 31; // 选择基数
mod = 1e9 + 9; // 选择模数
hash_value = computeHash(str);
}
// 获取哈希值
long long getHashValue() const {
return hash_value;
}
private:
long long computeHash(const std::string& str) {
long long hash = 0;
long long power = 1; // base^i
for (char c : str) {
hash = (hash + (c - 'a' + 1) * power) % mod; // 将字符转为数值
power = (power * base) % mod; // 更新 base^i
}
return hash;
}
long long hash_value;
long long base, mod;
};
int main() {
std::string s = "hello";
StringHash sh(s);
std::cout << "Hash value of '" << s << "' is: " << sh.getHashValue() << std::endl;
return 0;
}
```
### 原理讲解
1. **哈希函数**:
- 字符串中的每个字符被映射为一个数值(例如,`'a'` 映射为 1`'b'` 映射为 2依此类推
- 每个字符的数值根据其在字符串中的位置加权,位置越靠后,权重越大(由基数的幂决定)。
2. **模运算**:
- 使用模运算确保哈希值不会过大,并减少哈希冲突的可能性(即不同字符串生成相同哈希值的情况)。
3. **效率**:
- 哈希函数的计算复杂度为 O(n),适合快速比较和查找。
## 哈希冲突的常用处理方法
哈希冲突是指两个不同的输入数据经过哈希函数计算后产生相同的哈希值。解决哈希冲突的方法主要有以下几种:
1. **链地址法Separate Chaining**
- 为每个桶维护一个链表(或其他数据结构),将哈希值相同的元素存储在同一个链表中。
- 插入新元素时,计算哈希值并添加到对应的链表尾部。
2. **开放地址法Open Addressing**
- 在哈希表中寻找下一个空桶,使用一定的探查序列(如线性探查、二次探查或双重哈希)。
- 线性探查:在发生冲突时,检查下一个位置,直到找到空位。
- 二次探查:探查序列是某个二次方函数的值。
- 双重哈希:使用第二个哈希函数计算步长,解决冲突。
3. **再哈希Rehashing**
- 当哈希表达到某个负载因子时,重新计算哈希表的大小,使用新的哈希函数来分配所有元素。
4. **使用更好的哈希函数**
- 选择或设计一个更均匀的哈希函数,减少冲突的概率。
5. **结合使用不同的冲突解决方法**
- 根据具体应用场景,可以组合多种方法,提升性能和效率。
6. ....