【漫画算法】哈希表:古代皇帝的秘密魔法书

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容,和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣!

  • 推荐:数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注
    在这里插入图片描述

  • 导航

    • LeetCode解锁1000题: 打怪升级之旅:每题都包括3-5种算法,以及详细的代码实现,刷题面试跳槽必备
    • 漫画版算法详解:通过漫画的形式和动态GIF图片把复杂的算法每一步进行详细可视解读,看一遍就掌握
    • python源码解读:解读python的源代码与调用关系,快速提升代码质量
    • python数据分析可视化:企业实战案例:企业级数据分析案例与可视化,提升数据分析思维和可视化能力
    • 程序员必备的数学知识与应用:全面详细的介绍了工程师都必备的数学知识

期待与您一起探索技术、持续学习、一步步打怪升级 欢迎订阅本专栏❤️❤️

引言

在一个神秘的魔法世界里,有一本充满魔力的书,能够快速找到任何被记录的信息。这本书的秘密就在于它使用了一种叫做“哈希表”的魔法算法。本文将通过一个有趣的故事和简洁的漫画,向大家介绍哈希表的基本原理及其实现。

故事背景

在魔法王国中,皇帝拥有一本强大的魔法书,记录着王国里每个居民的信息。每当皇帝需要查找某个居民的信息时,他都能迅速找到。这本魔法书之所以如此强大,是因为它使用了哈希表这一神奇的算法。

角色介绍

  • 皇帝:魔法国王的智慧皇帝,掌握哈希表的秘密。
  • 大臣:国王的得力助手,听从皇帝解释和管理哈希表。
  • 居民:魔法王国的居民,他们的信息被记录在魔法书中。

故事展开

一天,皇帝决定向他的子民们揭示魔法书的秘密。他召集了所有大臣,并开始解释哈希表的原理。
在这里插入图片描述

漫画情节

场景1:国王解释哈希表的基本原理

皇帝展开一卷古老的卷轴,上面刻画着神秘的符号。他对大臣们说道:“这本魔法书之所以能快速找到任何居民的信息,秘密就在于一种叫做哈希表的算法。让我来解释其中的奥秘。”

皇帝继续说道:“首先,每个居民的名字(键)都会通过一个神奇的公式(哈希函数)转换成一个特定的数字(哈希值)。这个数字决定了信息在魔法书中的位置(索引)。例如,当我们插入‘Alice’的电话时,哈希函数会将她的名字转换为数字8,这样她的信息就会存储在索引8的位置。”

“但是,有时候不同的名字可能会被转换成相同的数字,这就是所谓的哈希冲突。比如,当我们插入‘Eve’的电话时,她的名字也被转换成了数字8。为了处理这种冲突,我们会在索引8的位置建立一个链表,将所有冲突的键值对串联起来。”

皇帝用手指着卷轴上的图示:“看,这里是我们目前的哈希表结构。”
插入键值对:居民名字与对应的电话号码。

  1. 插入 “Alice” 的电话:12345
  2. 插入 “Bob” 的电话:67890
  3. 插入 “Charlie” 的电话:54321
  4. 插入 “Dave” 的电话:98765
  5. 插入 “Eve” 的电话:11111

在这里插入图片描述

场景2:哈希函数的作用

在大殿内,皇帝继续向大臣们讲解哈希表的奥秘,重点介绍了哈希函数的作用。

哈希函数的定义

皇帝展开手中的卷轴,上面描绘着一个复杂而神秘的公式。他说道:“哈希函数是哈希表的核心,它的作用是将输入的键(比如居民的名字)转换成一个固定范围内的整数(哈希值)。这个整数决定了键值对在哈希表中的存储位置。”

哈希函数的作用

  1. 将键映射到索引
    皇帝用手指着卷轴上的公式,解释道:“通过哈希函数,我们可以将每个键映射到一个特定的索引位置。比如,名字‘Alice’通过哈希函数计算得到哈希值‘8’,所以她的信息将存储在索引‘8’的位置。”

  2. 均匀分布键值对
    皇帝继续说道:“哈希函数的设计目的是尽可能均匀地分布键值对在哈希表中,避免出现太多的哈希冲突。这有助于提高查找和插入操作的效率。”

  3. 快速查找
    “当我们需要查找某个键对应的值时,比如查找‘Charlie’的电话,只需通过哈希函数计算出哈希值‘6’,然后直接访问索引‘6’的位置,就能快速找到他的电话号码‘54321’。”

  4. 处理哈希冲突
    皇帝解释道:“尽管哈希函数的设计尽量避免冲突,但在某些情况下,不同的键可能会映射到相同的索引位置,这就是哈希冲突。比如,‘Alice’和‘Eve’都映射到索引‘8’。我们可以通过链表法将这些冲突的键值对存储在同一个索引位置的链表中。”

示例

皇帝举了一个例子来说明哈希函数的作用:

大臣们根据皇帝的指示,开始往魔法书(哈希表)中插入居民的信息。

插入 Alice 的电话:12345

  • 哈希值 = (A:65 + l:108 + i:105 + c:99 + e:101) % 10 = 478 % 10 = 8
  • 将 Alice 和她的电话号码插入到索引 8 的位置。

插入 Bob 的电话:67890

  • 哈希值 = (B:66 + o:111 + b:98) % 10 = 275 % 10 = 5
  • 将 Bob 和他的电话号码插入到索引 5 的位置。

插入 Charlie 的电话:54321

  • 哈希值 = (C:67 + h:104 + a:97 + r:114 + l:108 + i:105 + e:101) % 10 = 696 % 10 = 6
  • 将 Charlie 和他的电话号码插入到索引 6 的位置。

插入 Dave 的电话:98765

  • 哈希值 = (D:68 + a:97 + v:118 + e:101) % 10 = 384 % 10 = 4
  • 将 Dave 和他的电话号码插入到索引 4 的位置。

插入 Eve 的电话:11111

  • 哈希值 = (E:69 + v:118 + e:101) % 10 = 288 % 10 = 8
  • 发现索引 8 已经被 Alice 占用,发生哈希冲突。使用链表法将 Eve 添加到索引 8 的链表中。

皇帝总结道:“哈希函数的主要作用是将键转换成固定范围内的整数,从而确定键值对在哈希表中的存储位置。通过合理设计哈希函数,我们可以有效地分配存储空间,提高查找和插入操作的效率,并处理哈希冲突。”

大臣们听完后纷纷点头称赞,深刻理解了哈希函数在哈希表中的重要作用和工作原理。

场景3:处理哈希冲突

皇帝继续说道:“哈希表虽然高效,但有时会遇到哈希冲突。今天,我将讲解如何处理这些冲突。”

哈希冲突的产生

当不同的键映射到相同的索引时,就会发生哈希冲突。例如:

  • Alice:哈希值 8
  • Eve:哈希值 8

解决哈希冲突的方法

皇帝解释了几种常用的方法来处理哈希冲突:

  1. 链地址法(Separate Chaining)

    • 在每个索引位置维护一个链表,将冲突的键值对存储在链表中。
    • 优点:实现简单,冲突处理灵活。
    • 缺点:需要额外的存储空间来维护链表。

    示例

    Index  |  Key                |  Value
    ------------------------------------
      0    |                     |       
      1    |                     |       
      2    |                     |       
      3    |                     |       
      4    | Dave                |  98765
      5    | Bob                 |  67890
      6    | Charlie             |  54321
      7    |                     |       
      8    | Alice -> Eve        | 12345 -> 11111
      9    |                     |       
    
  2. 开放地址法(Open Addressing)

    • 当发生冲突时,寻找下一个空闲的位置来存储键值对。
    • 优点:不需要额外的存储空间。
    • 缺点:查找和插入的时间复杂度可能增加。

    常用的开放地址法包括

    • 线性探测(Linear Probing):按顺序查找下一个空闲位置。
    • 二次探测(Quadratic Probing):按平方序列查找空闲位置。
    • 双重哈希(Double Hashing):使用第二个哈希函数查找空闲位置。

通过这些方法,哈希表可以有效地处理哈希冲突,确保数据能够正确存储和快速查找。

哈希表的实现

class Node:
    def __init__(self, key, value):
        self.key = key
        self.value = value
        self.next = None

class HashTable:
    def __init__(self):
        self.size = 10
        self.table = [None] * self.size

    def hash_function(self, key):
        return sum(ord(char) for char in key) % self.size

    def insert(self, key, value):
        index = self.hash_function(key)
        new_node = Node(key, value)
        if self.table[index] is None:
            self.table[index] = new_node
        else:
            current = self.table[index]
            while current.next:
                if current.key == key:
                    current.value = value
                    return
                current = current.next
            if current.key == key:
                current.value = value
            else:
                current.next = new_node

    def search(self, key):
        index = self.hash_function(key)
        current = self.table[index]
        while current:
            if current.key == key:
                return current.value
            current = current.next
        return None

# 使用示例
hash_table = HashTable()
hash_table.insert("Alice", 12345)
hash_table.insert("Bob", 67890)
hash_table.insert("Charlie", 54321)
hash_table.insert("Dave", 98765)
hash_table.insert("Eve", 11111)

print("查找 'Alice' 的电话:", hash_table.search("Alice"))  # 输出: 12345
print("查找 'Eve' 的电话:", hash_table.search("Eve"))    # 输出: 11111

查找操作

查找 Alice 的电话号码

  1. 计算哈希值:hash_function(“Alice”) = 8
  2. 在索引 8 查找键值对:
  • 发现 Alice 的键,返回电话号码 12345。
    查找 Eve 的电话号码
  1. 计算哈希值:hash_function(“Eve”) = 8
  2. 在索引 8 查找键值对:
  • 发现 Alice 的键,不匹配,继续下一个节点。
  • 发现 Eve 的键,匹配,返回电话号码 11111。

哈希表的优点

  1. 快速查找:通过哈希函数,能够快速定位信息的位置。
  2. 灵活存储:适用于各种类型的数据存储和查找。
  3. 高效管理:在处理大量数据时,哈希表能够保持高效的性能。

以下是哈希表、数组和链表的优缺点及时间复杂度的比较表格:

数据结构优点缺点查找时间复杂度插入时间复杂度删除时间复杂度
哈希表- 平均情况下查找、插入和删除操作非常快,时间复杂度为 O(1)
- 动态扩展,适合处理大量数据
- 不需要有序
- 可能会发生哈希冲突,最坏情况下查找、插入和删除的时间复杂度为 O(n)
- 需要额外的空间来存储哈希函数和链表
- 适用于等值查找,不适用于区间查找
平均 O(1)
最坏 O(n)
平均 O(1)
最坏 O(n)
平均 O(1)
最坏 O(n)
数组- 支持快速随机访问,时间复杂度为 O(1)
- 存储结构简单,内存连续
- 插入和删除操作效率低,需要移动大量数据,时间复杂度为 O(n)
- 固定大小,动态调整需要重新分配内存
O(1)O(n)O(n)
链表- 动态大小,可以高效地进行插入和删除操作,时间复杂度为 O(1)
- 内存利用率高,不需要预分配空间
- 不支持高效的随机访问,查找时间复杂度为 O(n)
- 需要额外的内存存储指针,导致空间开销较大
O(n)O(1)O(1)

总结

通过这个故事,我们了解了哈希表的基本原理和实现方式。哈希表通过哈希函数快速定位数据,提高了查找效率,并且可以有效处理冲突。希望这篇文章和漫画能帮助大家更好地理解哈希表的工作原理。如果你对算法有更多的兴趣,欢迎关注我,了解更多有趣的算法故事!

🌹🌹如果觉得这篇文对你有帮助的话,记得一键三连关注、赞👍🏻、收藏是对作者最大的鼓励,非常感谢 ❥(^_-)

❤️❤️关注公众号 数据分析螺丝钉 回复 学习资料 领取高价值免费学习资料❥(^_-)
在这里插入图片描述

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

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

相关文章

三个有意思的链表面试题的完成

上一篇博客我们已经完成了链表的所有内容,那么这一篇博客我们来看一下三个特别有意思的链表题目。 **第一个题目如下:**相信不少朋友看到这题目就已经晕了,那就简单说明下这个题目,题目就是创建一个链表,其中每个节点…

软件构造复习1

一、软件构造的多维度视图: 共有三个维度:1.按阶段划分:构造时/运行时视图,2.按动态性划分:时刻/阶段视图,3.按构造对象层次划分:代码/构件视图 具体可如图所示(图片来自PPT&#…

数据库-SQL性能分析

SQL执行频率 慢查询日志 慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒)的所有 SQL语句的日志。 MySQL的慢查询日志默认没有开启,我们可以查看一下系统变量 slow_query_l…

掩码生成蒸馏——知识蒸馏

摘要 https://arxiv.org/pdf/2205.01529 知识蒸馏已成功应用于各种任务。当前的蒸馏算法通常通过模仿教师的输出来提高学生的性能。本文表明,教师还可以通过指导学生的特征恢复来提高学生的表示能力。从这一观点出发,我们提出了掩码生成蒸馏&#xff08…

Redis常见基本类型(5)-List, Set

List 命令小结 命令及解释时间复杂度lpush/rpush key value[key value...](向右/左端插入元素)O(k), k是元素个数linsert key before | after pivot value(在某个坐标之前/右插入元素)O(n), n是pivot距离头尾的距离lrange start end(获取从start到end部分的元素)O(s n): s是…

与用户沟通获取需求的方法

1 访谈 访谈是最早开始使用的获取用户需求的技术,也是迄今为止仍然广泛使用的需求分析技术。 访谈有两种基本形式,分别是正式的和非正式的访谈。正式访谈时,系统分析员将提出一些事先准备好的具体问题,例如&#xff0…

Java使用apache.poi生成excel插入word中

加油,新时代打工人! 工作需求,上个文章我们生成好的word,这次将生成好的excel表格数据,插入word中。需要准备好excle数据,然后插入到word中。 最后个需要,就是把这些生成好的word文档转成pdf进行…

基础技术-ELF系列(1)-ELF文件基础

成就更好的自己 本篇是基础技术系列中ELF相关技术的首篇文章。 尽管网上有许多关于ELF相关内容的文章,但总体而言,要么是一些非常基础且重复性强的内容,要么直接深入探讨相对高深的主题,缺乏系统化分析和解释。 接下来&#xf…

C++技能进阶指南——多态语法剖析

前言:多态是面向对象的三大特性之一。顾名思义, 多态就是多种状态。 那么是什么的多种状态呢? 这里的可能有很多。比如我们去买火车票, 有普通票, 学生票; 又比如我们去旅游, 有儿童票&#xff…

10款免费黑科技软件,强烈推荐!

1.AI视频生成——巨日禄 网页版https://aitools.jurilu.com/ "巨日禄 "是一款功能强大的文本视频生成器,可以快速将文本内容转换成极具吸引力的视频。操作简单,用户只需输入文字,选择喜欢的样式和模板, “巨日禄”就会…

Nginx - 安全基线配置与操作指南

文章目录 概述中间件安全基线配置手册1. 概述1.1 目的1.2 适用范围 2. Nginx基线配置2.1 版本说明2.2 安装目录2.3 用户创建2.4 二进制文件权限2.5 关闭服务器标记2.6 设置 timeout2.7 设置 NGINX 缓冲区2.8 日志配置2.9 日志切割2.10 限制访问 IP2.11 限制仅允许域名访问2.12 …

【408真题】2009-16

“接”是针对题目进行必要的分析,比较简略; “化”是对题目中所涉及到的知识点进行详细解释; “发”是对此题型的解题套路总结,并结合历年真题或者典型例题进行运用。 涉及到的知识全部来源于王道各科教材(2025版&…

qemu+gdb调试linux内核

打开CONFIG_DEBUG_INFO,编译内核 通过图形菜单配置该宏,执行make menuconfig。 kernel hacking —> compile-time checks and compiler options —> compile the kernel with debug info 验证是否打开成功,grep -nr “CONFIG_DEBUG_INFO” .config。 打开成功,然后…

AcWing 3466. 清点代码库(STL:map,vector)

3466. 清点代码库 需要求有几种不同数列&#xff0c;每种有多少个&#xff0c;可以想到用map。它的键是一个数列&#xff0c;可以把它放在vector里。也就是map<vector<int>,int> 要满足要求的输出序列&#xff0c;就要想把它放在其他容器&#xff0c;或数组里&…

【Linux】信号之信号的保存和处理详解

&#x1f916;个人主页&#xff1a;晚风相伴-CSDN博客 &#x1f496;如果觉得内容对你有帮助的话&#xff0c;还请给博主一键三连&#xff08;点赞&#x1f49c;、收藏&#x1f9e1;、关注&#x1f49a;&#xff09;吧 &#x1f64f;如果内容有误或者有写的不好的地方的话&…

仿《Q极速体育》NBACBA体育直播吧足球直播综合体育直播源码

码名称&#xff1a;仿《Q极速体育》NBACBA体育直播吧足球直播综合体育直播源码 开发环境&#xff1a;帝国cms7.5 空间支持&#xff1a;phpmysql 仿《Q极速体育》NBACBA体育直播吧足球直播综合体育直播源码自动采集 - 我爱模板网源码名称&#xff1a;仿《Q极速体育》NBACBA体育直…

编程实战:自己编写HTTP服务器(系列3:处理框架)

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 系列入口&#xff1a;编程实战…

需求分析部分图形工具

描述复杂的事物时,图形远比文字叙述优越得多,它形象直观容易理解。前面已经介绍了用于建立功能模型的数据流图、用于建立数据模型的实体-联系图和用于建立行为模型的状态图,本节再简要地介绍在需求分析阶段可能用到的另外3种图形工具。 1 层次方框图 层次方框图用树形结…

LaTex 模板 - 东北师范大学申研申博推荐信

文章目录 NENU-Letter-Template项目地址示例特性项目结构如何使用main.texletterContent.tex 如何编译方式 1 &#xff1a;在线编译方式 2 &#xff1a;本地编译 参考 NENU-Letter-Template NENU’s recommendation letter template. 东北师范大学推荐信模板 项目地址 GitHu…

Spring框架学习笔记(五):JdbcTemplate 和 声明式事务

基本介绍&#xff1a;通过 Spring 框架可以配置数据源&#xff0c;从而完成对数据表的操作。JdbcTemplate 是 Spring 提供的访问数据库的技术。将 JDBC 的常用操作封装为模板方法 1 JdbcTemplate 使用前需进行如下配置 1.1 在maven项目的pom文件加入以下依赖 <dependencies…