一、简介和应用哈希表(Hash Table)是一种高效的数据结构,通过哈希函数将键(Key)映射到存储位置,实现O(1)时间复杂度的查找、插入和删除操作。它广泛应用于缓存系统、数据库索引、字典查询等场景。例如,在编程中需要快速根据用户ID查找信息时,哈希表能显著提升效率。本文将通过手写的C++哈希表代码,带您从零开始理解其实现原理。 二、特点和注意事项1. 特点: 快速访问:通过哈希函数直接定位数据,避免线性查找。 动态扩容:本例中默认大小为1000,可自定义大小(但需注意扩容策略未在代码中实现)。 冲突解决:使用链地址法(即每个哈希桶存储链表),解决不同键映射到同一地址的问题。 2. 注意事项: 哈希函数设计:需尽量均匀分布,减少冲突(本例用取模运算,简单但可能不均)。 内存管理:代码中使用了new动态分配节点,但未显式释放,实际应用需考虑内存泄漏风险。 链表长度:若冲突过多,链表过长可能导致性能下降,需优化哈希函数或改用其他策略。 三、实现步骤1. 定义数据结构: 使用pairs结构体存储键值对(key和val)。 listnode节点包含值及指向下一个节点的指针,形成链表。 hash_map类维护哈希表数组(存储链表头指针)和表大小。 2. 构造函数: 默认或传入指定大小初始化数组,并全部置空。 3. 核心方法: ins():计算键的哈希地址,新建节点插入链表末尾(处理头节点为空和冲突情况)。 del():定位键的哈希地址,遍历链表删除对应节点(需判断头节点是否为目标)。 find():查找并返回指定键的值,未找到则返回-1。 print():遍历整个哈希表输出所有键值对。 4. 冲突处理:通过链表串联同一地址下的多个元素,避免数据覆盖。 四、代码和注释- #include <iostream>
- using namespace std;
- // 键值对结构体
- struct pairs {
- int key; // 键
- int val; // 值
- };
- // 链表节点(存储键值对)
- template<typename T>
- struct listnode {
- T val; // 节点值
- listnode* next = nullptr; // 指向下一个节点
- // 构造节点
- listnode() {} // 空构造
- listnode(T v) { val = v; } // 传入值构造
- };
- // 哈希表类
- class hash_map {
- private:
- listnode<pairs>** map; // 存储链表头指针的数组
- int size; // 哈希表大小
- public:
- // 默认构造函数(初始化大小为1000)
- hash_map() {
- size = 1000;
- map = new listnode<pairs>*[size]; // 动态分配数组
- for (int i = 0; i < size; i++) { // 初始化所有位置为空
- map[i] = nullptr;
- }
- }
- // 指定大小构造函数
- hash_map(int size) {
- this->size = size; // 使用传入的大小
- map = new listnode<pairs>*[size];
- for (int i = 0; i < size; i++) {
- map[i] = nullptr;
- }
- }
- // 插入键值对
- void ins(pairs pair) {
- int address = pair.key % size; // 哈希函数:取模定位地址
- listnode<pairs>* newnode = new listnode<pairs>(pair); // 创建新节点
- listnode<pairs>* tmp = map[address]; // 当前地址的链表头
- if (!tmp) { // 若头节点为空,直接插入
- map[address] = newnode;
- return;
- }
- while (tmp->next) { // 否则遍历到链表末尾
- tmp = tmp->next;
- }
- tmp->next = newnode; // 插入末尾
- }
- // 删除指定键
- void del(int key) {
- int address = key % size; // 定位地址
- listnode<pairs>* tmp = map[address];
- if (tmp->val.key == key) { // 若头节点就是目标
- map[address] = map[address]->next; // 删除头节点
- return;
- }
- while (tmp->next->val.key!= key) { // 遍历查找目标节点
- tmp = tmp->next;
- }
- tmp->next = tmp->next->next; // 删除目标节点
- }
- // 查找指定键的值
- int find(int key) {
- int address = key % size;
- listnode<pairs>* tmp = map[address];
- while (tmp && tmp->val.key!= key) { // 遍历查找
- tmp = tmp->next;
- }
- if (!tmp) return -1; // 未找到返回-1
- return tmp->val.val; // 返回值
- }
- // 打印所有键值对
- void print() {
- for (int i = 0; i < size; i++) {
- listnode<pairs>* tmp = map[i];
- while (tmp) { // 遍历当前地址的链表
- cout << tmp->val.key << ":" << tmp->val.val << " ";
- tmp = tmp->next;
- }
- cout << endl; // 换行分隔不同地址
- }
- cout << endl;
- }
- };
复制代码
五、总结通过本文的代码与注释,您已初步掌握了哈希表的核心实现逻辑:利用哈希函数映射键到地址,通过链表解决冲突,从而实现高效的增删查操作。实际应用中,需进一步优化哈希函数(如使用更均匀的算法)和考虑内存管理。建议新手从简单示例入手,逐步实践,理解数据结构背后的设计思想,为后续学习更复杂算法打下基础。
|