欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 手游 > 哈希表与哈希算法:原理、实现与优化

哈希表与哈希算法:原理、实现与优化

2025/3/20 7:03:08 来源:https://blog.csdn.net/liudadaxuexi/article/details/146382906  浏览:    关键词:哈希表与哈希算法:原理、实现与优化

哈希表与哈希算法:原理、实现与优化

1. 哈希表基础原理

哈希表(Hash Table)是一种基于键值对(key-value)存储数据的数据结构,它通过计算键的哈希值来确定数据在内存中的存储位置,从而实现O(1)平均时间复杂度的插入、查找和删除操作。

1.1 哈希表的核心组件

  1. 哈希函数:将任意大小的输入数据映射到固定大小的输出(哈希值)
  2. 哈希桶(数组):存储数据的实际容器
  3. 冲突解决机制:处理不同键映射到相同位置的情况

1.2 哈希表的基本原理

哈希表通过以下步骤存储和检索数据:

  1. 通过哈希函数计算键的哈希值
  2. 将哈希值映射到哈希桶的索引位置
  3. 在该位置存储或检索数据
  4. 如果发生冲突,使用冲突解决策略处理

2. 哈希函数设计

哈希函数是哈希表性能的关键因素,一个好的哈希函数应该具备以下特性:

  1. 高效计算:计算速度快
  2. 均匀分布:不同输入产生的哈希值均匀分布在整个输出范围内
  3. 确定性:相同的输入总是产生相同的输出
  4. 雪崩效应:输入的微小变化会导致输出的显著变化

2.1 常见的哈希函数

2.1.1 整数哈希

对于整数类型的键,常用的哈希函数包括:

// 简单的取模哈希函数
size_t hash_mod(int key, size_t table_size) {return key % table_size;
}// 乘法哈希函数(Knuth推荐)
size_t hash_multiply(int key, size_t table_size) {const double A = 0.6180339887; // (sqrt(5) - 1) / 2double val = key * A;val = val - floor(val);return floor(val * table_size);
}
2.1.2 字符串哈希

对于字符串类型的键,几种经典哈希算法:

// BKDR哈希算法
size_t BKDRHash(const char* str, size_t table_size) {unsigned int seed = 131; // 31, 131, 1313, 13131... 都是不错的选择unsigned int hash = 0;while (*str) {hash = hash * seed + (*str++);}return hash % table_size;
}// FNV哈希算法
size_t FNVHash(const char* str, size_t table_size) {const unsigned int FNV_PRIME = 16777619;const unsigned int OFFSET_BASIS = 2166136261;unsigned int hash = OFFSET_BASIS;while (*str) {hash ^= *str++;hash *= FNV_PRIME;}return hash % table_size;
}// Jenkins哈希算法(one-at-a-time)
size_t JenkinsHash(const char* str, size_t table_size) {unsigned int hash = 0;while (*str) {hash += *str++;hash += (hash << 10);hash ^= (hash >> 6);}hash += (hash << 3);hash ^= (hash >> 11);hash += (hash << 15);return hash % table_size;
}

2.2 选择哈希表大小

哈希表的大小也是影响性能的重要因素。通常,选择质数作为哈希表大小可以减少冲突:

// 检查一个数是否为质数
bool isPrime(int n) {if (n <= 1) return false;if (n <= 3) return true;if (n % 2 == 0 || n % 3 == 0) return false;for (int i = 5; i * i <= n; i += 6) {if (n % i == 0 || n % (i + 2) == 0) return false;}return true;
}// 找到大于n的下一个质数
int nextPrime(int n) {if (n <= 1) return 2;int prime = n;bool found = false;while (!found) {prime++;if (isPrime(prime)) found = true;}return prime;
}

3. 冲突解决策略

哈希冲突是指不同的键通过哈希函数计算后得到相同的哈希值。解决冲突的主要策略有两种:开放寻址和链式寻址。

3.1 链式寻址(Chaining)

链式寻址使用链表存储映射到同一位置的所有元素:

  1. 每个哈希桶维护一个链表
  2. 发生冲突时,将新元素添加到链表中
  3. 查找时,遍历链表找到目标元素

优点:

  • 实现简单
  • 对负载因子不敏感
  • 插入操作不受表大小限制

缺点:

  • 需要额外的内存存储链表
  • 可能导致缓存不友好
  • 搜索时间与链表长度相关

3.2 开放寻址(Open Addressing)

开放寻址在冲突发生时,通过某种探测序列查找下一个可用位置:

3.2.1 线性探测(Linear Probing)

冲突发生时,按顺序检查下一个位置:

size_t linear_probe(size_t hash, size_t i, size_t table_size) {return (hash + i) % table_size;
}

优点:

  • 缓存友好
  • 内存利用率高

缺点:

  • 容易造成聚集(clustering)
  • 负载因子增大时性能下降明显
3.2.2 二次探测(Quadratic Probing)

使用二次方程确定探测序列:

size_t quadratic_probe(size_t hash, size_t i, size_t table_size) {return (hash + i*i) % table_size;
}

优点:

  • 减少了聚集问题
  • 比线性探测性能更稳定

缺点:

  • 可能无法探测表中所有位置
3.2.3 双重哈希(Double Hashing)

使用第二个哈希函数确定步长:

size_t double_hash(size_t hash1, size_t hash2, size_t i, size_t table_size) {return (hash1 + i * hash2) % table_size;
}

优点:

  • 消除二次聚集
  • 提供更均匀的探测序列

缺点:

  • 计算开销略大

4. 哈希表的C++实现

以下是使用链式寻址实现的哈希表:

#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <functional>template<typename K, typename V>
class HashMap {
private:// 哈希表的桶,每个桶是一个链表std::vector<std::list<std::pair<K, V>>> buckets;size_t size_;size_t capacity_;double load_factor_threshold_;// 哈希函数size_t hash(const K& key) const {return std::hash<K>{}(key) % buckets.size();}// 重新哈希void rehash() {size_t new_capacity = nextPrime(capacity_ * 2);std::vector<std::list<std::pair<K, V>>> new_buckets(new_capacity);for (const auto& bucket : buckets) {for (const auto& pair : bucket) {size_t bucket_idx = std::hash<K>{}(pair.first) % new_capacity;new_buckets[bucket_idx].push_back(pair);}}buckets = std::move(new_buckets);capacity_ = new_capacity;}// 查找大于n的

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词