js(JavaScript)数据结构之散列表(Hash)

什么是数据结构?

下面是维基百科的解释:

数据结构是计算机存储、组织数据的方式。数据结构意味着接口或封装:一个数据结构可被视为两个函数之间的接口,或者是由数据类型联合组成的存储内容的访问方法封装。

我们每天的编码中都会用到数据结构,下面是常见的数据结构:

  • 数组(Array)
  • 栈(Stack)
  • 队列(Queue)
  • 链表(Linked List)
  • 散列表(Hash)
  • 字典
  • 树(Tree)
  • 图(Graph)
  • 堆(Heap)

散列表(Hash)

散列表(Hash)是一种常用的数据结构,用于存储键值对。它利用散列函数将键映射到一个数字索引上,以便快速地插入、删除和查找数据。在JavaScript 中,可以使用对象来实现散列表的功能。

特点

  • 快速操作:在散列表上插入、删除和取用数据都非常快。
  • 低效率查找:对于查找操作来说却效率低下。

设计目的

用数组或链表存储数据时,若想要找到其中一个数据,需要从头进行遍历,因为不知道这个数据存储在数组的哪个位置。散列表通过散列函数将键映射为一个数字,使得数据存储在特定位置,从而提高了查找效率。

JavaScript中的实现

在 JavaScript 中,散列表可以基于对象进行设计。数组的长度是预先设定的,所有元素根据与该元素对应的键,保存在数组的特定位置。这里的键和对象的键是类型的概念。当使用散列表存储数组时,通过一个散列函数将键映射为一个数字,这个数字的范围是0到散列表的长度。

案例参考

以下是一个使用散列表存储学生信息的案例 HTML/JS 效果,其中使用了一个自己实现的散列表,实现了基本的插入、删除和查找操作:

HTML代码:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Student Info</title>
</head>
<body><input type="text" placeholder="输入名字" id="nameInput"><input type="text" placeholder="输入成绩" id="scoreInput"><button onclick="addStudent()">添加学生</button><br><br><input type="text" placeholder="输入要搜索的名字" id="searchInput"><button onclick="searchStudent()">搜索学生</button><br><br><label for="result">结果: </label><span id="result"></span><script src="hashTable.js"></script>
</body>
</html>

JavaScript代码:

// 自定义散列函数function hashFunction(key) {var hash = 0;for (var i = 0; i < key.length; i++) {hash += key.charCodeAt(i);}return hash % 100; // 假设散列表有 100 个位置}// 自定义散列表类function HashTable() {this.table = new Array(100); // 创建一个大小为 100 的数组作为散列表this.add = function (key, value) {var index = hashFunction(key);this.table[index] = value;};this.remove = function (key) {var index = hashFunction(key);this.table[index] = undefined;};this.find = function (key) {var index = hashFunction(key);return this.table[index];};}// 创建一个散列表实例用于存储学生信息var studentHash = new HashTable();// 根据输入添加学生信息function addStudent() {var name = document.getElementById("nameInput").value;var score = document.getElementById("scoreInput").value;studentHash.add(name, score);console.log(studentHash.table);}// 根据输入查找学生的成绩function searchStudent() {var name = document.getElementById("searchInput").value;var score = studentHash.find(name);if (score !== undefined) {document.getElementById("result").textContent = score;} else {document.getElementById("result").textContent = "没有找到相关数据";}}

上述代码中,首先定义了一个散列函数 hashFunction,该函数将输入的键通过字符编码相加并取余操作,得到散列的索引。然后创建了一个自定义的散列表类 HashTable,内部使用一个大小为 100 的数组作为散列表的存储结构。散列表的 add() 方法根据键的散列值将值存储到相应的位置上,remove() 方法按键的散列值将相应位置的值置为 undefined,find() 方法根据键的散列值查找对应的值。

在 HTML 中,通过输入框和按钮来添加学生,并通过另一个输入框和按钮来查找学生的成绩。在 JS 的实现中,添加学生和查找学生都是通过散列表的 add() 和 find() 方法实现的。当添加学生时,根据学生的姓名计算出散列值,然后将对应的成绩存储到散列表中。当查找学生时,根据输入的姓名计算出散列值,并在散列表中查找对应的成绩,最后将结果在页面上展示出来。

总体来说,上述代码实现了使用散列表存储学生信息的基本功能。

散列表(Hash)中的碰撞解决方法

在散列表中,当两个不同的键被映射到相同的位置时,就会发生碰撞。为了解决这个问题,有两种常见的方法:开链法和线性探测法。

1. 开链法

开链法是一种简单而直观的碰撞解决方法。它使用数组来存储散列中的每个槽位,每个槽位都是一个链表或者数组。当发生碰撞时,新的键值对会被添加到对应槽位的链表或数组上。

示例:
假设我们有一个散列表,其中包含10个槽位。当发生碰撞时,我们将键值对存储在对应槽位的链表或数组中。例如,如果键 “apple” 和 “banana” 都被映射到槽位 3,并且已经有一个键值对 “apple: red” 存储在该位置上,那么 “banana: yellow” 将会被添加到 “apple: red” 后面,形成一个链表或数组。

2. 线性探测法

线性探测法是另一种处理碰撞的方法。当发生碰撞时,线性探测法会顺序地检查下一个槽位,直到找到一个空的槽位来存储新的键值对。

示例:
假设我们有一个散列表,其中包含10个槽位。当发生碰撞时,线性探测法会依次检查下一个槽位,直到找到一个空的槽位。例如,如果键 “apple” 被映射到槽位 3,但该位置已经被占用,线性探测法会继续检查槽位 4、5 直到找到一个空的槽位来存储 “apple: red”。

这两种方法提供了灵活的方式来处理散列表中的碰撞,确保即使发生碰撞,仍然能够有效地存储和检索数据。

开链法(Chaining)

优点:
  1. 简单易懂: 开链法实现起来比较简单,容易理解和实现。
  2. 适用于大量数据: 当数据量很大时,开链法能够有效地处理碰撞,因为每个槽位都可以容纳多个键值对。
缺点:
  1. 额外空间开销: 使用链表或数组来解决碰撞需要额外的存储空间,可能导致内存浪费。
  2. 性能不稳定: 如果链表过长,查找某个键的时间复杂度可能变得较高,导致性能不稳定。

线性探测法(Linear Probing)

优点:
  1. 节省空间: 相比开链法,线性探测法不需要额外的链表或数组,节省了一些空间。
  2. 缓存友好: 连续的存储位置对缓存更友好,有助于提高访问效率。
缺点:
  1. 聚集问题: 线性探测法可能导致聚集问题,即连续位置上出现大量的键,增加了后续插入的冲突概率。
  2. 删除操作复杂: 删除操作相对复杂,因为需要保证删除后的位置后面的元素都能正确找到。

如何选择:

  • 如果对内存空间要求较高,而且对性能的稳定性要求不那么严格,可以选择开链法。
  • 如果内存空间相对充足,而且希望在大规模数据下有更稳定的性能,可以选择线性探测法。

总体来说,选择开链法还是线性探测法取决于具体应用场景和对性能、内存的不同需求。

持续学习总结记录中,回顾一下上面的内容:
散列表(Hash)是一种常用的数据结构,用于存储键值对。它利用散列函数将键映射到一个数字索引上,以便快速地插入、删除和查找数据。在JavaScript 中,可以使用对象来实现散列表的功能。

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

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

相关文章

web学习笔记(十五)

目录 1.Date对象 1.1日期对象的概念 1.2Date()方法的使用 1.3Date()常用方法汇总 1.4例题&#xff1a;用函数编写一个倒计时 2.函数 2.1函数的概念 2.2函数的使用 2.3函数的参数 2.4函数的声明 2.5函数的返回值 2.6异步函数 3特殊函数类型 3.1匿名函数 3.2箭头函数…

前端开发中需要注意的CSS命名规则以及书写顺序

1、CSS的命名——BEM规则&#xff1a; CSS命名一般是用 BEM 规则命名的。它背后的想法是将用户界面划分为独立的块。 BEM的意思就是B模块(block)、E元素(element)、M修饰符(modifier)&#xff0c; 即&#xff1a;[block]__[element]--[modifier]。 模块和子元素之间用两个下划…

SPARK--cache(缓存)和checkpoint检查点机制

SPARK–cache(缓存)和checkpoint检查点机制 rdd的特性 缓存和checkpoint 作用都是进行容错rdd在计算是会有多个依赖&#xff0c;为了避免计算错误是从头开始计算&#xff0c;可以将中间* 依赖rdd进行缓存或checkpoint缓存或checkpoint也叫作rdd的持久化一般对某个计算特别复杂的…

[Flutter] extends、implements、mixin和 abstract、extension的使用介绍说明

类创建&#xff1a;abstract&#xff08;抽象类&#xff09;、extension&#xff08;扩展&#xff09; 1.abstract&#xff08;抽象类&#xff09; dart 抽象类主要用于定义标准&#xff0c;子类可以继承抽象类&#xff0c;也可以实现抽象类接口。抽象类通过abstract 关键字来…

一端进,两端出(队列)C++

*给定一个输入受限的双端队列&#xff08;即一个端点允许插入和删除&#xff0c;另一个端点只允许删除的双端队列&#xff09;和一个长度为 N 的插入序列。插入序列中的元素两两不同。你需要将插入序列中的元素按顺序依次插入到给定队列中。 在插入过程中和插入完成后的任意时…

【软件测试】学习笔记-静态测试方法

这篇文章详细讨论人工静态测试方法和自动静态测试方法&#xff0c;来帮你理解研发流程上是如何保证代码质量的&#xff0c;以及如何搭建自己的自动静态代码扫描方案&#xff0c;并且应用到项目的日常开发工作中去。 人工静态方法本质上属于流程上的实践&#xff0c;实际能够发…

QEMU源码全解析 —— PCI设备模拟(7)

接前一篇文章&#xff1a; 上一回讲解了pci_edu_realize函数中的pci_register_bar函数&#xff0c;本回开始对于edu设备的MMIO读写函数进行解析。 操作系统与PCI设备交互的主要方式是PIO和MMIO。MMIO虽然是一段内存&#xff0c;但是其没有EPT映射&#xff0c;在虚拟机访问设备…

Smallpdf扫描、转换、压缩、编辑、签名PDF

【应用名称】&#xff1a;Smallpdf: 扫描、转换、压缩、编辑、签名PDF 【适用平台】&#xff1a;#Android 【软件标签】&#xff1a;#Smallpdf 【应用版本】&#xff1a;1.71.0 【应用大小】&#xff1a;150MB 【软件说明】&#xff1a;通过 Smallpdf&#xff0c;您可以&…

数据结构 模拟实现二叉树(孩子表示法)

目录 一、二叉树的简单概念 &#xff08;1&#xff09;关于树的一些概念 &#xff08;2&#xff09;二叉树的一些概念及性质 定义二叉树的代码&#xff1a; 二、二叉树的方法实现 &#xff08;1&#xff09;createTree &#xff08;2&#xff09;preOrder &#xff08;…

资源三号03星-立体测绘卫星星座

资源三号03星作为我国民用高分辨率立体测图卫星资源三号系列的第三颗卫星&#xff0c;在资源三号02星技术状态的基础上进行了继承和适当优化&#xff0c;设计寿命由资源三号02星的5年延长至8年&#xff0c;星上搭载了三线阵立体测绘相机、多光谱相机和业务化应用的激光测高仪&a…

【模型评估 07】过拟合与欠拟合

在模型评估与调整的过程中&#xff0c;我们往往会遇到“过拟合”或“欠拟合”的情况。如何有效地识别“过拟合”和“欠拟合”现象&#xff0c;并有针对性地进行模型调整&#xff0c;是不断改进机器学习模型的关键。特别是在实际项目中&#xff0c;采用多种方法、从多个角度降低…

C#使用CryptoStream类加密和解密字符串

目录 一、CrytoStream的加密方法 二、CrytoStream的解密方法 三、实例 1.源码Form1.cs 2.类库Encrypt.cs 3.生成效果 在使用CryptoStream前要先引用命名空间using System.Security.Cryptography。 一、CrytoStream的加密方法 记住&#xff0c;不能再使用DESCryptoServi…

DrGraph原理示教 - OpenCV 4 功能 - 边界填充

今天简单来看一下OpenCV中的边界填充 param src Source image. param dst Destination image of the same type as src and the size Size(src.colsleftright, src.rowstopbottom) . param top the top pixels param bottom the bottom pixels param left the left pixels par…

Photoshop 2024 (PS2024) v25 直装版 支持win/mac版

Photoshop 2024 提供了多种创意工具&#xff0c;如画笔、铅笔、涂鸦和渐变等&#xff0c;用户可以通过这些工具来创建独特和令人印象深刻的设计效果。增强的云同步&#xff1a;通过 Adobe Creative Cloud&#xff0c;用户可以方便地将他们的工作从一个设备无缝同步到另一个设备…

docker关闭所有容器的命令

关闭所有容器的命令是docker stop $(docker ps -aq)&#xff0c;其中&#xff1a; 使用docker ps -a命令列出所有的容器&#xff1b; 实现方法1&#xff1a;使用docker ps -a命令获取所有容器的ID&#xff0c;然后使用docker stop命令逐个停止容器。 实现方法2&#xff1a;使用…

STM32L051使用HAL库操作实例(14)- ADC采集电压

目录 一、前言 二、ADC外设简要说明 三、STM32CubeMX配置&#xff08;本文使用的STM32CubeMX版本为6.1.2&#xff09; 1.MCU选型 2.时钟使能 3.外部时钟配置 4.串口配置 5.ADC引脚配置 6.配置STM32CubeMX生成工程文件 7.点击GENERATE CODE生成工程文件 四、工程源码 …

Python基础知识:整理13 利用pyecharts生成折线图

首先需要安装第三方包pyecharts 1 基础折线图 # 导包&#xff0c;导入Line功能构建折线图对象 from pyecharts.charts import Line # 折线图 from pyecharts.options import TitleOpts # 标题 from pyecharts.options import LegendOpts # 图例 from pyecharts.options im…

mp4文件全部转换为mp3

问题 今天突发奇想&#xff0c;想把mp4视频转换为mp3来收听&#xff0c;于是想到了ffmpeg工具 步骤 安装ffmpeg环境 要在 Windows 上配置 FFmpeg 环境&#xff0c;你可以按照以下步骤进行操作&#xff1a; 下载 FFmpeg&#xff1a; 首先&#xff0c;你需要下载 FFmpeg 的 W…

一个成功的camera案例:ros2+gazebo+摄像头

各位看&#xff1a;随着大物体的移动&#xff0c;在涉嫌头的位置也发生了改变-----右上角那个/camera的位置也变了 右上角那个是摄像头图案&#xff0c;以下是仓库链接&#xff1a; ros-ign-gazebo-camera: https://github.com/arashsm79/ros-ign-gazebo-camera.git一个ros2摄…

初识物联网

1&#xff1a;什么是IOT&#xff1a; 物联网的英文名称是Internet of Things。IoT则是Internet of Things的缩写。因此, 物联网 IoT。 通俗地说&#xff0c;物联网是互联网的一种拓展。我们知道互联网是由无数的计算机和智能手机交错连接而编织成的一张网。而正是有了像NodeM…