【每日算法】Day 6-1:哈希表从入门到实战——高频算法题(C++实现)

摘要 :掌握高频数据结构!今日深入解析哈希表的核心原理与设计实现,结合冲突解决策略与大厂高频真题,彻底掌握O(1)时间复杂度的数据访问技术。

一、哈希表核心思想

哈希表(Hash Table) 是一种基于键值对的高效数据结构,通过哈希函数将键映射到存储位置,核心特性:

  • 平均时间复杂度:插入、删除、查找均为O(1)

  • 冲突处理:开放寻址法、链地址法等策略

  • 负载因子:哈希表性能的关键指标(元素数/桶数)

应用场景 :

  • 快速数据检索

  • 去重操作

  • 缓存系统设计(如LRU Cache)

二、哈希表实现原理

1. 哈希函数设计

理想哈希函数特性 :

  • 确定性:相同键的哈希值始终相同

  • 均匀性:键值均匀分布到各个桶

  • 高效性:计算速度快

常见哈希函数 :

  • 除法哈希:hash(key) = key % capacity

  • 乘法哈希:利用黄金分割点

  • 多项式哈希:用于字符串处理

cpp 复制代码
// 字符串哈希示例(多项式滚动哈希)
size_t stringHash(const string& s, size_t mod = 1e9+7) {
    size_t hash = 0;
    const size_t base = 31; // 常用质数基数
    for (char c : s) {
        hash = (hash * base + c) % mod;
    }
    return hash;
}

2. 冲突解决策略

动态示意图 :

链地址法示意图

策略1:链地址法(Separate Chaining)

cpp 复制代码
// 哈希表节点定义
template <typename K, typename V>
struct HashNode {
    K key;
    V value;
    HashNode* next;
    HashNode(K k, V v) : key(k), value(v), next(nullptr) {}
};

// 哈希表类框架
template <typename K, typename V>
class HashMap {
private:
    vector<HashNode<K,V>*> buckets;
    size_t capacity;
    size_t size;
    
    size_t hashFunction(K key) {
        return hash<K>{}(key) % capacity;
    }
    
public:
    HashMap(size_t cap = 16) : capacity(cap), size(0) {
        buckets.resize(cap, nullptr);
    }
    
    // 插入、查找、删除操作实现...
};

策略2:开放寻址法(Open Addressing)

cpp 复制代码
// 线性探测插入实现
template <typename K, typename V>
void HashMap<K,V>::put(K key, V value) {
    size_t index = hashFunction(key);
    while (buckets[index] != nullptr) {
        if (buckets[index]->key == key) { // 已存在则更新
            buckets[index]->value = value;
            return;
        }
        index = (index + 1) % capacity; // 线性探测
    }
    buckets[index] = new HashNode<K,V>(key, value);
    size++;
}

三、哈希表操作实现(C++)

1. 插入操作(链地址法)

cpp 复制代码
template <typename K, typename V>
void HashMap<K,V>::put(K key, V value) {
    size_t index = hashFunction(key);
    HashNode<K,V>* node = buckets[index];
    while (node) { // 检查键是否已存在
        if (node->key == key) {
            node->value = value;
            return;
        }
        node = node->next;
    }
    // 头插法添加新节点
    HashNode<K,V>* newNode = new HashNode<K,V>(key, value);
    newNode->next = buckets[index];
    buckets[index] = newNode;
    size++;
}

2. 查找操作、

cpp 复制代码
template <typename K, typename V>
V HashMap<K,V>::get(K key) {
    size_t index = hashFunction(key);
    HashNode<K,V>* node = buckets[index];
    while (node) {
        if (node->key == key) {
            return node->value;
        }
        node = node->next;
    }
    throw out_of_range("Key not found");
}

3. 删除操作

cpp 复制代码
template <typename K, typename V>
void HashMap<K,V>::remove(K key) {
    size_t index = hashFunction(key);
    HashNode<K,V>* node = buckets[index];
    HashNode<K,V>* prev = nullptr;
    
    while (node) {
        if (node->key == key) {
            if (prev) prev->next = node->next;
            else buckets[index] = node->next;
            delete node;
            size--;
            return;
        }
        prev = node;
        node = node->next;
    }
}

四、复杂度与优化

操作 平均情况 最坏情况
插入 O(1) O(n)
删除 O(1) O(n)
查找 O(1) O(n)

优化策略 :

  • 负载因子监控:当元素数/桶数超过阈值(如0.75),触发扩容

  • 动态扩容:容量扩展为原来的2倍,并重新哈希所有元素

  • 良好的哈希函数选择:减少冲突,提升性能

相关推荐
loulanyue_22 分钟前
构建房产认知决策智能:Harness底座与AI自进化的技术实践——读贝壳首席算法科学家尹俊希2026云栖专场演讲
人工智能·算法
碧海银沙音频科技研究院33 分钟前
基于炬芯ATS录音卡BLE控制协议
人工智能·嵌入式硬件·算法·语音识别
jimy11 小时前
C++ 虚函数表:基类和派生类共用一张 vtable 吗?
开发语言·c++
爱吃提升1 小时前
Dev-C++ 5.11 C++断点调试完整教程
开发语言·c++
suhan1 小时前
【数据结构】三、栈和队列:6.链队列、双端队列、队列的应用(树的层次遍历、广度优先BFS、先来先服务FCFS)
数据结构·后端·算法
姜鱼问生1 小时前
Docker Volume 备份与恢复实战:不停机迁移数据
后端·算法·架构
suhan1 小时前
【数据结构】三、栈和队列:5.顺序队列(循环队列)(初始化,判空判满,入队,出队,实例)
数据结构·后端·算法
suhan1 小时前
【数据结构】三、栈和队列:3.链栈(链栈栈的初始化,判空,进栈,出栈,读取栈顶,链栈实例)
数据结构·后端·算法
大雄很用心1 小时前
如何理解时间复杂度与空间复杂度?| 面试刷题笔记02
算法
姜鱼问生1 小时前
服务器磁盘满了?从告警到清理的完整排查
后端·算法·架构