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

news2025/3/29 16:59:44

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

一、哈希表核心思想

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

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

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

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

应用场景

  • 快速数据检索

  • 去重操作

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

二、哈希表实现原理

1. 哈希函数设计

理想哈希函数特性

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

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

  • 高效性:计算速度快

常见哈希函数

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

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

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

// 字符串哈希示例(多项式滚动哈希)
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)

// 哈希表节点定义
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)

// 线性探测插入实现
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. 插入操作(链地址法)

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. 查找操作、

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. 删除操作

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倍,并重新哈希所有元素

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2322115.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SPPAS安装及问题汇总

SPPAS下载地址 文件找不到&#xff0c;可能是MAC的自动化操作问题&#xff0c;解决方案有二&#xff1a; 方案一&#xff1a; 直接查看SPPAS中的readme&#xff0c;运行sppas.command 方案二&#xff1a; 在自动化脚本中添加 export PATH/usr/local/bin:$PATH

LINUX基础 [三] - 进程创建

目录 前言 进程创建的初次了解&#xff08;创建进程的原理&#xff09; 什么是fork函数&#xff1f; 初识fork函数 写时拷贝 fork函数存在的意义 fork调用失败的原因 进程终止 运行完毕结果不正确 main函数返回 库函数函数exit 系统调用接口_exit 进程异常终止 进…

【day1】数据结构刷题 链表

一 反转链表 206. 反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]…

鼠标在客户区内按下左键和双击右键

书籍&#xff1a;《Visual C 2017从入门到精通》的2.6鼠标 环境&#xff1a;visual studio 2022 内容&#xff1a;【例2.44】鼠标在客户区内按下左键和双击右键 1.创建一个单文档程序 一个简单的单文档程序-CSDN博客https://blog.csdn.net/qq_20725221/article/details/1463…

c++ map和vector模板类

在这一章中C语法之模板函数和模板类-CSDN博客 我们学习了怎样写模板函数和模板类&#xff0c;接下来我们来学习系统给我们写好的两个模板类:map和vector。 我相信有了上文的基础&#xff0c;能帮助我们更好的理解这些模板类。 map和vector 是C STL(标准模板库) 中的一部分&a…

hn航空app hnairSign unidbg 整合Springboot

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 逆向分析 学习unidbg补环境。先弄一个…

Arm Linux ceres库编译

由于工作需要&#xff0c;需在国产化系统上编译ceres库&#xff0c;手上有一块树莓派&#xff0c;就在树莓派上面进行测试编译ceres库&#xff0c;总体来说比较顺利。只出现了一点小问题 参考链接&#xff1a; Ceres中文教程-安装 Ceres官方网站&#xff08;英文&#xff09; …

矩阵补充,最近邻查找

矩阵补充&#xff0c;最近邻查找 矩阵补充是向量召回最简单的一种方法&#xff0c;现在不常用&#xff0c;学习矩阵补充是为了更好的理解后面学到的双塔模型 下图&#xff0c;输入用户ID和物品ID后从Eebedding层拿到对应的向量做内积&#xff0c;内积的结果就是矩阵补充 模型…

gradio调用多个CSS的HTML页

很多博客介绍的gradio读取html和css比较简单&#xff0c;如果要做很细致的前端页面优化&#xff0c;比如丰富的响应式的cssjs&#xff0c;至少要有html多个css&#xff0c;是暂不能实现的。bootstrap、font-awesome、jquery等 方案一当然是直接更换htmlcss为主的部署方式&#…

NVIDIA NeMo 全面教程:从入门到精通

NVIDIA NeMo 全面教程&#xff1a;从入门到精通 文章目录 NVIDIA NeMo 全面教程&#xff1a;从入门到精通目录框架介绍NeMo的核心特点NeMo的架构NeMo与其他框架的比较NeMo的模型集合NeMo的工作流程NeMo 2.0的新特性 安装指南系统要求使用Docker容器安装步骤1&#xff1a;安装Do…

Thales靶机攻略

1.下载导入VBox&#xff0c;并启动靶机 靶机地址&#xff1a;https://download.vulnhub.com/thales/Thales.zip 解压后&#xff0c;在VBox中导入虚拟电脑。包含所有网卡的MAC地址。 导入完成&#xff0c;设置网卡模式为仅主机网络。开启靶机。 kali网卡更改为桥接模式。点击工…

尝试使用Tauri2+Django+React项目(2)

前言 尝试使用tauri2DjangoReact的项目-CSDN博客https://blog.csdn.net/qq_63401240/article/details/146403103在前面笔者不知道怎么做&#xff0c;搞了半天 笔者看到官网&#xff0c;原来可以使用二进制文件&#xff0c;好好好 嵌入外部二进制文件 | Taurihttps://v2.taur…

6.1 模拟专题:LeetCode 1576. 替换所有的问号

1. 题目链接 LeetCode 1576. 替换所有的问号 2. 题目描述 给定一个仅包含小写字母和问号 ? 的字符串 s&#xff0c;要求将所有 ? 替换为任意小写字母&#xff0c;使得替换后的字符串中 没有相邻的两个字符相同。 示例&#xff1a; 输入&#xff1a;s "?zs" →…

Linux安装go环境

安装一个lazydocker&#xff0c;根据文档需要先安装go环境 https://github.com/jesseduffield/lazydocker 官方文档解析 https://go.dev/doc/install 文档内容如下&#xff0c;一共三步 1.删除先前安装的go&#xff0c;解压下载的go压缩包到/usr/local目录 2.添加环境变量&…

卡特兰数在数据结构上面的运用

原理 Catalan数是一个数列&#xff0c;其第n项表示n个不同结点可以构成的二叉排序树的数量。Catalan数的第n项公式为&#xff1a; &#xfffc; 其中&#xff0c;&#xfffc;是组合数&#xff0c;表示从2n个元素中选择n个元素的组合数。 Catalan数的原理可以通过以下方式理解&…

悟空crm v12安装好后出现 网络错误问题(已解决)

请求网址: http://wwww.aaaa.com/gateway/adminUser/queryUserNumInfo 请求方法: POST 状态代码: 502 Bad Gateway 远程地址: 101.37.79.226:9807 引荐来源网址政策: strict-origin-when-cross-origin

便携版:随时随地,高效处理 PDF 文件

PDF-XChange Editor Plus 便携版是一款功能强大且极其实用的 PDF 阅读与编辑工具。它不仅支持快速浏览 PDF 文件&#xff0c;还提供了丰富的编辑功能&#xff0c;让用户可以轻松处理 PDF 文档。经过大神优化处理&#xff0c;这款软件已经变得十分轻便&#xff0c;非常适合需要随…

【Golang】补充:占位符、转义字符、错误处理

&#x1f525; 个人主页&#xff1a;星云爱编程 &#x1f525; 所属专栏&#xff1a;Golang &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 1、占位符 1.1通用占位符 %v &#xff1a;默认格式的值。适…

文件上传绕过的小点总结(4)

9.末尾点删除处理缺陷 给出源码&#xff1a; $file_name trim($_FILES[upload_file][name]); $file_name deldot($file_name);//删除文件名末尾的点 $file_ext strrchr($file_name, .); $file_ext strtolower($file_ext); //转换为小写 $file_ext str_ireplace(::$DATA,…

如何用Spring AI构建MCP Client-Server架构

现代 Web 应用正加速与大语言模型(LLMs)深度融合,构建超越传统问答场景的智能解决方案。为突破模型知识边界,增强上下文理解能力,开发者普遍采用多源数据集成策略,将 LLM 与搜索引擎、数据库、文件系统等外部资源互联。然而,异构数据源的协议差异与格式壁垒,往往导致集…