深入解析哈希表:原理、实现与应用

目录

一、哈希表是什么?

1.1 基本概念

1.2 哈希表的工作原理

二、哈希表的使用方法

2.1 C++ 标准库中的哈希表

示例:std::unordered_map 的基本用法

2.2 自定义哈希函数

示例:自定义哈希函数

三、什么时候使用哈希表?

3.1 适用场景

3.2 不适用场景

四、哈希表的优缺点

4.1 优点

4.2 缺点

五、哈希表的实现细节

5.1 冲突解决策略

5.2 动态扩容

示例:动态扩容的实现

六、总结


一、哈希表是什么?

1.1 基本概念

哈希表是一种基于键值对(Key-Value Pair)存储的数据结构,通过哈希函数将键映射到表中的某个位置,从而实现快速访问。哈希表的核心组成部分包括:

  • 键(Key):用于唯一标识数据的值。

  • 值(Value):与键关联的数据。

  • 哈希函数(Hash Function):将键映射到哈希表索引的函数。

  • 桶(Bucket):存储键值对的容器,通常是一个数组或链表。

1.2 哈希表的工作原理

  1. 插入

    • 计算键的哈希值:hash_value = hash(key)

    • 根据哈希值确定存储位置:index = hash_value % table_size

    • 将键值对存储到对应的桶中。

  2. 查找

    • 计算键的哈希值。

    • 根据哈希值定位桶。

    • 在桶中查找键对应的值。

  3. 删除

    • 计算键的哈希值。

    • 根据哈希值定位桶。

    • 在桶中删除键值对。


二、哈希表的使用方法

2.1 C++ 标准库中的哈希表

C++ 标准库提供了 std::unordered_map 和 std::unordered_set,分别用于存储键值对和键集合。

示例:std::unordered_map 的基本用法
#include <iostream>
#include <unordered_map>
#include <string>

int main() {
    // 创建一个哈希表
    std::unordered_map<std::string, int> map;

    // 插入键值对
    map["apple"] = 1;
    map["banana"] = 2;
    map["cherry"] = 3;

    // 查找键
    if (map.find("banana") != map.end()) {
        std::cout << "banana found: " << map["banana"] << std::endl;
    }

    // 删除键
    map.erase("cherry");

    // 遍历哈希表
    for (const auto& pair : map) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}

输出:

banana found: 2
apple: 1
banana: 2

2.2 自定义哈希函数

C++ 标准库的 std::hash 支持基本类型和字符串,但对于自定义类型,需要特化 std::hash

示例:自定义哈希函数
#include <iostream>
#include <unordered_map>
#include <string>

struct MyKey {
    int id;
    std::string name;

    bool operator==(const MyKey& other) const {
        return id == other.id && name == other.name;
    }
};

namespace std {
    template<>
    struct hash<MyKey> {
        size_t operator()(const MyKey& k) const {
            return hash<int>()(k.id) ^ (hash<string>()(k.name) << 1);
        }
    };
}

int main() {
    std::unordered_map<MyKey, int> map;
    map[{1, "apple"}] = 10;
    map[{2, "banana"}] = 20;

    MyKey key = {1, "apple"};
    if (map.find(key) != map.end()) {
        std::cout << "Found: " << map[key] << std::endl;
    }

    return 0;
}

输出:

Found: 10

三、什么时候使用哈希表?

3.1 适用场景

  1. 快速查找

    • 当需要频繁查找数据时,哈希表可以提供接近常数时间复杂度的性能。

    • 示例:字典、电话簿、缓存系统。

  2. 去重

    • 哈希表可以高效地检测和删除重复元素。

    • 示例:统计唯一单词数量。

  3. 关联数据存储

    • 当需要存储键值对时,哈希表是一种理想的数据结构。

    • 示例:数据库索引、配置文件解析。

3.2 不适用场景

  1. 范围查询

    • 哈希表不支持范围查询(如查找大于某个值的所有键)。

    • 适用数据结构:平衡二叉搜索树(如 std::map)。

  2. 内存受限环境

    • 哈希表需要额外的内存存储哈希值和桶结构。

    • 在内存受限的环境中,可能需要选择更紧凑的数据结构。


四、哈希表的优缺点

4.1 优点

  1. 高效的操作

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

  2. 灵活性

    • 支持任意类型的键和值(需提供哈希函数)。

  3. 易于实现

    • C++ 标准库提供了现成的实现(std::unordered_map)。

4.2 缺点

  1. 冲突问题

    • 不同的键可能映射到相同的哈希值,导致性能下降。

  2. 内存开销

    • 需要额外的内存存储哈希值和桶结构。

  3. 无序性

    • 哈希表中的元素是无序的(std::unordered_map)。


五、哈希表的实现细节

5.1 冲突解决策略

  1. 链地址法(Separate Chaining)

    • 每个桶存储一个链表,冲突的元素被添加到链表中。

    • 优点:简单易实现,适合高装载因子。

    • 缺点:链表过长时性能下降。

  2. 开放寻址法(Open Addressing)

    • 所有元素存储在哈希表的数组中,冲突时通过探测函数寻找下一个空闲位置。

    • 优点:缓存友好,适合低装载因子。

    • 缺点:删除操作复杂,容易产生聚集现象。

5.2 动态扩容

当哈希表的装载因子超过阈值时,会触发扩容操作:

  1. 创建一个更大的桶数组。

  2. 重新计算所有键的哈希值并插入新数组。

  3. 释放旧数组。

示例:动态扩容的实现
template<typename K, typename V>
class HashTable {
private:
    std::vector<std::list<std::pair<K, V>>> buckets;
    size_t bucket_count;
    size_t element_count;
    double max_load_factor = 0.75;

    size_t hash(const K& key) const {
        return std::hash<K>{}(key) % bucket_count;
    }

    void rehash() {
        size_t new_bucket_count = bucket_count * 2;
        std::vector<std::list<std::pair<K, V>>> new_buckets(new_bucket_count);

        for (const auto& chain : buckets) {
            for (const auto& pair : chain) {
                size_t new_index = std::hash<K>{}(pair.first) % new_bucket_count;
                new_buckets[new_index].push_back(pair);
            }
        }

        buckets = std::move(new_buckets);
        bucket_count = new_bucket_count;
    }

public:
    HashTable(size_t count = 10) : bucket_count(count), element_count(0) {
        buckets.resize(bucket_count);
    }

    void insert(const K& key, const V& value) {
        if ((double)element_count / bucket_count > max_load_factor) {
            rehash();
        }
        size_t index = hash(key);
        auto& chain = buckets[index];
        chain.emplace_back(key, value);
        element_count++;
    }
};

六、总结

        哈希表是一种高效的数据结构,适用于需要快速查找、插入和删除的场景。C++ 标准库提供了 std::unordered_map 和 std::unordered_set,可以方便地使用哈希表。在实际开发中,需要根据具体需求选择合适的哈希函数和冲突解决策略,并注意哈希表的装载因子和内存开销。通过深入理解哈希表的原理和实现细节,可以更好地利用其优势解决实际问题。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CentOS-Stream 9更换RT实时内核

文章目录 1 安装环境1.1 Centos9原生内核示意 2 下载实时内核3 CentOS更换阿里YUM源3.1 更换源3.2 添加文件内容3.2.1 centos.repo3.2.2 centos-addons.repo 3.3 yum源生效 4 安装epel-release5 安装必要库和软件6 配置内核6.1 更改内核文件权限6.2 使用tar命令解压内核源码文件…

微软AutoGen高级功能——Magentic-One

介绍 大家好&#xff0c;博主又来给大家分享知识了&#xff0c;这次给大家分享的内容是微软AutoGen框架的高级功能Magentic-One。那么它是用来做什么的或它又是什么功能呢&#xff0c;我们直接进入正题。 Magentic-One Magnetic-One是一个通用型多智能体系统&#xff0c;用于…

国产编辑器EverEdit - 极简追梦人的福音:迷你查找

1 迷你查找 1.1 应用场景 某些场景下&#xff0c;用户不希望调出复杂的查找对话框&#xff0c;此时可以使用迷你查找窗口。 1.2 使用方法 选择主菜单查找 -> 迷你查找&#xff0c;或使用快捷键Ctrl Alt F&#xff0c;会在右上角弹出迷你查找窗口&#xff0c;如下图所示…

【第4章:循环神经网络(RNN)与长短时记忆网络(LSTM)— 4.5 序列标注与命名实体识别】

一、引言 嘿,各位技术小伙伴们!今天咱们要来深入聊聊循环神经网络(RNN)和长短时记忆网络(LSTM),这俩在序列标注和命名实体识别领域那可是相当厉害的角色。咱就从最基础的概念开始,一步步揭开它们神秘的面纱,看看它们到底是怎么在实际应用中发挥巨大作用的。 二、序列…

AIGC与AICG的区别解析

目录 一、AIGC&#xff08;人工智能生成内容&#xff09; &#xff08;一&#xff09;定义与内涵 &#xff08;二&#xff09;核心技术与应用场景 &#xff08;三&#xff09;优势与挑战 二、AICG&#xff08;计算机图形学中的人工智能&#xff09; &#xff08;一&#x…

DeepSeek 助力 Vue 开发:打造丝滑的卡片(Card)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

采购订单不计算MRP的供给问题

采购订单不计算MRP的供给问题。MD04的例外信息20 20的例外信息的意思&#xff1a;重复需求&#xff0c;建议取消。也就是不算MRP的供给。 MRP最大运行期间的配置 MRP最大运行期间是指MRP运行时考虑的时间范围。配置路径为&#xff1a; 事务码&#xff1a;OMDX 或通过路径&…

DeepSeek处理自有业务的案例:让AI给你写一份小众编辑器(EverEdit)的语法着色文件

1 DeepSeek处理自有业务的案例&#xff1a;让AI给你写一份小众编辑器(EverEdit)的语法着色文件 1.1 背景 AI能力再强&#xff0c;如果不能在企业的自有业务上产生助益&#xff0c;那基本也是一无是处。将企业的自有业务上传到线上训练&#xff0c;那是脑子进水的做法&#xff…

LeetCode 热题 100_组合总和(58_39_中等_C++)(递归(回溯))

LeetCode 热题 100_组合总和&#xff08;58_39&#xff09; 题目描述&#xff1a;输入输出样例&#xff1a;题解&#xff1a;解题思路&#xff1a;思路一&#xff08;递归&#xff08;回溯&#xff09;&#xff09;&#xff1a; 代码实现代码实现&#xff08;思路一&#xff08…

2024年12月电子学会青少年机器人技术等级考试(五级)理论综合真题

202412 青少年等级考试机器人理论真题五级 一、单选题 第 1 题 ESP32 for Arduino&#xff0c;下列选项中&#xff0c;具有根据电容量的变化&#xff0c;获取返回值的函数是&#xff1f;&#xff08; &#xff09; A&#xff1a;touchRead() B&#xff1a;digitalRead() C&…

京东获得JD商品详情 API 返回值说明||京东API接口

item_get-获得JD商品详情 .jd.item_get 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_search_sh…

Halcon相机标定

1&#xff0c;前言。 相机的成像过程实质上是坐标系的转换。首先空间中的点由“世界坐标系”转换到“相机坐标系”&#xff0c;然后再将其投影到成像平面&#xff08;图像物理坐标系&#xff09;&#xff0c;最后再将成像的平面上的数据转换为图像像素坐标系。但是由于透镜的制…

学习星开源在线考试教育系统

学习星开源考试系统 项目介绍 项目概述&#xff1a; 学习星在线考试系统是一款基于Java和Vue.js构建的前后端分离的在线考试解决方案。它旨在为教育机构、企业和个人提供一个高效、便捷的在线测试平台&#xff0c;支持多种题型&#xff0c;包括但不限于单选题、多选题、判断…

趣味魔法项目 LinuxPDF —— 在 PDF 中启动一个 Linux 操作系统

最近&#xff0c;一位开源爱好者开发了一个LinuxPDF 项目&#xff08;ading2210/linuxpdf: Linux running inside a PDF file via a RISC-V emulator&#xff09;&#xff0c;它的核心功能是在一个 PDF 文件中启动并运行 Linux 操作系统。它通过巧妙地使用 PDF 文件格式中的 Ja…

k8s的安装

1. k8s的安装 192.168.48.6 master01 192.168.481.6 node01 192.168.48.26 node02 三台机器一起操作 1.swapoff -a &#xff1a;关闭交换分区 2. iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X 3. cat > /etc/sy…

Sentinel 持久化配置

前言 在微服务架构中&#xff0c;Sentinel 是一个非常流行的流量控制和熔断组件&#xff0c;它可以帮助我们保护系统免受高流量的冲击。然而&#xff0c;Sentinel 的配置在默认情况下是不持久化的&#xff0c;这意味着一旦服务重启&#xff0c;所有配置就会丢失。为了解决这个…

不到1M的工具,使用起来非常丝滑!

今天给大家推荐两款电脑上超实用的小软件&#xff0c;分别是倒计时工具和关机助手&#xff0c;用起来特别顺手&#xff0c;希望能帮到大家。 关机助手 帮你自动关机 先说说关机助手。这款软件简直太方便了&#xff01;它是一款免安装的小工具&#xff0c;体积超小&#xff0c;…

day9手机创意软件

趣味类 in:记录趣味生活&#xff08;通用&#xff09; 魔漫相机&#xff1a;真人变漫画&#xff08;通用&#xff09; 活照片&#xff1a;让照片活过来&#xff08;通用&#xff09; 画中画相机&#xff1a;与众不同的艺术 年龄检测仪&#xff1a;比一比谁更年轻&#xf…

【前端 DevOps】GitHub Actions 与 GitLab CI 实战:实现前端项目的自动化测试与部署

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…

无耳科技 Solon v3.0.8 发布,Java 企业级应用开发框架

Solon 框架&#xff01; Solon 是新一代&#xff0c;Java 企业级应用开发框架。是杭州无耳科技有限公司的“根级”开源项目&#xff08;最近“杭州六小龙”很火啊&#xff0c;我们也是杭州的哦&#xff09;。从零开始构建&#xff08;No Spring、No Java-EE、No Servlet&#…