JS中的字典和散列表

news2024/11/8 18:37:39

前言

        除了集合,我们还可以用字典和散列表来存储唯一值。

        集合学习请见:

自定义集合和ES6集合http://t.csdn.cn/RcznA        在集合中,我们关注的是每个值本身。并将它作为主要元素。

        而字典和散列表都是以[键:值]的形式来存储数据。

        不同的是,字典的每一个键只能有一个值。

字典

        字典和集合很相似。其存储的都是一组互不相同的元素。集合以[值:值]的形式存储元素。而字典以[键:值]的形式存储元素。字典也称为映射符号表或关联数组

        在计算机科学中,字典常用来保存对象的引用地址。

字典类

        ES6提供了一个Map类的实现。即上文所说的字典。

        现在我们讲讲自行的实现:

export default class Dictionary {
  constructor() {
    this.table = {};
  }
}

        与我们自定义的Set类相似,我们都将在一个Object的实例而不是数组中存储字典中的元素。

        在JS中,[]可以获取对象的属性。将属性名作为“位置”传入即可。所以对象也被称为关联数组。

规划化键名

       在字典中,理想情况是用字符串作为键名。值可以是任何类型。所以我们需要确保key为字符串类型。于是我们需要先定义一个类型转换方法。确保所有key键都为字符串类型。

export default class Dictionary {
  constructor(toStrFn = defaultToString) {
    this.toStrFn = toStrFn;
    this.table = {};
  }
}

          除非用户自定义转化方法。一般的转化方法我们可以这么书写:

function defaultToString(item) {
  if (item === null) {
    return 'NULL';
  } else if (item === undefined) {
    return 'UNDEFINED';
  } else if (typeof item === 'string' || item instanceof String) {
    return `${item}`;
  }
  return JSON.stringify(item);
}

检测键是否存在于字典中

hasKey(key) {
    return Object.getOwnPropertyNames.call(this.toStrFn(key),this.table)
}

在字典中设置键

        首先我们要搞清楚要以什么方式去储存键值。上面已经提过是[键名:键值]这种方式。键名为字符串。那么键值呢?

        键名的字符串是经过转换的。而为了保存信息的需要,我们同样要保存原始的key。于是我们需要在键值Value里面记录原始的key和value。于是我们需要设置一个ValuePair类。用于存储原始数据。

class ValuePair {
    constructor(key, value) {
        this.key = key;
        this.value = value;
    }
}

        书写Set方法

set(key,value) {
    if (key != null && value !=null && !this.hasKey(key)) {
        const tableKey = this.toStrFn(key);
        this.table[tableKey ] = new ValuePair(key, value)
        return true
    }
    return false
}

在字典中移除一个键值对

  remove(key) {
    if (this.hasKey(key)) {
      delete this.table[this.toStrFn(key)];
      return true;
    }
    return false;
  }

在字典中检索键值对

  get(key) {
    const valuePair = this.table[this.toStrFn(key)];
    return valuePair == null ? undefined : valuePair.value;
  }

        或者

get(key) {
    if (this.hasKey(key)) {
        return this.table[this.toStriFn(key)]
    }else {
        return undefined
    }
}

        但是第二种方法我们需要获取两次Key的字符串已经访问两次table对象。第一次的消耗明显更小

以数组的方式返回字典中所有的原始数据(包括key和value)

keysAndValues() {
    return Object.values(this.table)
}

        这使用了ES6的方法。我们也可以写成通用的方法:

keysAndValues() {
    const values = [];
    for (const k in this.table) {
        if (this.hasKey(k)) {
            values.push(this.table[k])
        }
    }
    return values
}

        为什么要加hasKey进行判断呢?

        因为for…in循环是 遍历对象的每一个可枚举属性,包括原型链上面的可枚举属性

Object.keys()只是遍历自身的可枚举属性,不可以遍历原型链上的可枚可枚举属性Object.getOwnPropertyNames()则是遍历自身不包括原型链上面的所有属性(不论是否是可枚举的),

        由此我们知道,for in循环可能枚举原型链上的属性。而且还有一个原因是可能是通过extend进行的类扩展,用for in可能枚举父类上的字段属性

keys方法返回原始数据键名 

  keys() {
    return this.keysAndValues().map(valuePair => valuePair.key);
  }

        如果不支持ES6,可以用for循环替代map方法

values方法返回原始数据键值

values() {
    return this.keysAndValues().map(valuePair => valuePair.value)
}

自定义字典的forEach迭代

        我们需要创建一个能迭代这种数据结构中每个键值的方法。同时允许我们注入回调函数callbackFn并通过回调函数返回的结果中断迭代。

forEach(callbackFn) {
    const valuePairs = this.keyAndValues();
    for (let i = 0; i < valuePairs.length; i++) {
        const result =  callBackFn(valuePairs[i].key,valuePairs[i].value)
        if (result === false) {
            break;
        }
    }
}

size方法

返回字典中键的个数

size() {
    const valuePairs = this.keyAndValues()
    return valuePairs.length
}

clear方法

clear() {
    this.table = {}
}

isEmpty方法

  isEmpty() {
    return this.size() === 0;
  }

toString方法

 toString() {
    if (this.isEmpty()) {
      return '';
    }
    const valuePairs = this.keyValues();
    let objString = `${valuePairs[0].toString()}`;
    for (let i = 1; i < valuePairs.length; i++) {
      objString = `${objString},${valuePairs[i].toString()}`;
    }
    return objString;
  }

散列表

        HashTable类,也叫HashMap类。它是字典类的一种散列表实现方式。

作用

        在字典里,如果要找到你想要的值(不是键,也不是健和值,而是值)。需要遍历整个数据结构来找到它。

散列算法与散列函数

        狭义的算法常用的有排序、递归、动态规划、贪心算法、散列算法等等

        数据结构常用的有数组、对象、堆栈、队列、链表、集合(Set 类)、字典(Map 类)、散列表(以及散列集合)、二叉树等等。

        散列算法的作用是尽可能快地在数据结构中找到一个值

        散列函数的作用是给定一个健值,然后返回值在表中的地址。

        我们前面已经提到了,数组和链表的差别在于前者是检索很快,有一个下标就能快速定位到值,但是插入和删除项就没有后者强,而后者不需要像数组一样,改动一个项,其他的项在内存中的位置也会跟着变化,但是检索却更慢,因为要从头部或者尾部开始寻找。

        那么如果像数组、对象或者是集合这些数据结构,配合散列算法(就是散列函数)使用的话,那么可以达到插入和检索的性能都很高的效果。

案例:

        我们要维护一个数据结构,这个结构要存储以健为人名,以值为邮箱,业务需求是要不断往里面新增新的项,或者删除项,并且检索的频率也很高。

        我们用最常见的散列函数lose lose散列函数进行存值。

        lose lose散列函数:方法是简单地将每个健值中的每个字符的 ASCII 值相加。

        最终的 key 的存储方式就是每个字符的 ASCII 值相加的结果。

        散列函数代码:

loseloseHashCode(key) {
    if (typeof key === 'number') {
      return key;
    }
    const tableKey = this.toStrFn(key);
    let hash = 0;
    for (let i = 0; i < tableKey.length; i++) {
      hash += tableKey.charCodeAt(i);
    }
    return hash % 37;
}
hashCode(key) {
    return this.loseloseHashCode(key);
}

        这里为什么要取余数?为了得到比较小的hash值。我们会使用hash和一个任意数做除法的余数。这样可以规避操作数超过数值变量最大表示范围的风险                

案例实现:

        我们基于一个关联数组(对象)来表示我们的数据结构。

class HashTable {
  constructor(toStrFn = defaultToString) {
    this.toStrFn = toStrFn;
    this.table = {};
  }
} 

put方法 向散列表中增加一个新的项(此方法会更新散列表)

put(key,value) {
    if (key !=null && value != null) {
        const position = this.hashCode(key)
        this.table[position] = new ValuePair(key,value);
        return true
    }
    return false
}

get方法 从散列表中获取一个值 

get(key) {
    const valuePair = this.table[this.hashCode(key)]
    return valuePair  == null ? undefined : valuePair.value
}

        HashTable和Dictionary类很相似。不同之处在于在字典类中,我们将valuePair保存在table的key属性中(在它呗转换为字符串之后)。而在HashTable中,我们将key生成一个数(键),并将valuerPair保存在值,从而形成一张新的hash表。

  remove(key) {
    const hash = this.hashCode(key);
    const valuePair = this.table[hash];
    if (valuePair != null) {
      delete this.table[hash];
      return true;
    }
    return false;
  }

我们也可以把散列表称为散列映射

以上为字典和散列表的基础介绍,如果需要了解散列表的进阶应用,请看下一篇推文《JavaScript散列表及其扩展》

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

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

相关文章

Linux中vim的预备代码(prepare-code)设置

1、进入以下目录&#xff1a; /home/yys/.vim/plugged/prepare-code/snippet注意&#xff1a;yys是我个人的账号名称&#xff0c;每个人的都不一样&#xff01; 2、修改相应的预备代码&#xff0c;比如snippet.c 修改完之后保存&#xff0c;之后再创建c文件则会自动初始化有…

Python如何免费获取付费文档的数据, 保存word文档

目录标题 前言开发环境:模块使用:代码实现步骤:代码展示尾语 前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 开发环境: python 3.8 pycharm 模块使用: requests --> pip install requests re json time base64 docx --> pip install python-docx 第三方模…

【C++初阶】string类常见题目详解(二) —— 把字符串转换成整数、反转字符串、反转字符串 II、反转字符串中的单词 III、字符串相乘

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;C初阶 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;C初阶】s…

ElasticSearch学习02——Kibana安装

ElasticSearch学习02——Windows下Kibana安装 Kibana是界面化的查询数据的工具&#xff0c;下载时尽量下载与ElasicSearch一致的版本。 1、下载对应版本的Kibana ​ 有了ElasticSearch安装的经验&#xff0c;我们发现了ES和JDK有着版本对应的关系&#xff0c;Kibana和ES共同为…

【Linux基础命令】nmtui命令使用实战

前言 linux常用命令专栏已进入尾声&#xff0c;大约90个命令是日常工作中常用的&#xff0c;在拓展一些不常用的&#xff0c;也就100左右。 是不是总结下来后&#xff0c;就感觉要学的内容没有那么多了。 当然有些专属的基础命令不在本专栏内&#xff0c;比如LVM管理命令&am…

微信读书:从Paxos到Zookeeper:分布式一致性原理与实践(阅读摘录)

微信读书&#xff1a;从Paxos到Zookeeper&#xff1a;分布式一致性原理与实践&#xff08;阅读摘录&#xff09; 阅读地址 CAP理论 CAP理论告诉我们&#xff0c;一个分布式系统不可能同时满足一致性(C&#xff1a;Consistency)、可用性(A&#xff1a;Availability)和分区容错…

Andriod 开发 SearchView默认弹出软键盘

SearchView默认弹出软键盘&#xff0c;遮挡了主界面 这很明显是SearchView是默认自动获取了焦点&#xff0c;所以上网搜了一下如何清除焦点&#xff1a; SearchView searchView getActivity().findViewById(R.id.searchViewSearchbar); searchView.clearFocus(); 然而没用&…

零拷贝原理

在实际应用中&#xff0c;如果我们需要把磁盘中的某个文件内容发送到远程服务器上&#xff0c;那么它必 须要经过几个拷贝的过程。从磁盘中读取目标文件内容拷贝到内核缓冲区&#xff0c;CPU 控制器再把内核缓冲区的数据赋值到用户空间的缓冲区中&#xff0c; 接着在应用程序中…

Arrays类概述,Lambda表达式

数组操作工具类&#xff0c;专门用于操作数组元素 2&#xff1a;常用API Lambda概述 Lambda表达式是JDK开始后的一种新语法形式作用&#xff1a;简化匿名内部类的代码写法 格式&#xff1a; 注意&#xff1a;Lambda表达式只能简化函数式接口的匿名内部类的写法形式。 什么是…

JAVA-编程基础-07-面向对象思想

Lison <dreamlison163.com>, v1.0.0, 2023.03.26 JAVA-编程基础-07-面向对象思想 文章目录 JAVA-编程基础-07-面向对象思想一、三大特性封装继承多态 二、类图泛化关系 (Generalization)实现关系 (Realization)聚合关系 (Aggregation)组合关系 (Composition)关联关系 (A…

使用vim编辑器,进行保存时报错:E382: Cannot write, ‘buftype‘ option is set

目录 一、背景 1.1使用vim 进行:wq保存时&#xff0c;报错&#xff1a;E382: Cannot write, buftype option is set 1.2 产生原因 二、解决 2.1 解决办法 2.2 还原 一、背景 1.1使用vim 进行:wq保存时&#xff0c;报错&#xff1a;E382: Cannot write, buftype option i…

【UnityDOTS 二】Entity的理解

Entity的理解 Entity作为一种对CPU的Cache友好的编码方式&#xff0c;是DOTS中重要的编码流程与思想。需要程序员由OOP的思想转为DOD的思想&#xff0c;即&#xff1a;面向数据的编码方式。 Unity的ECS&#xff1a; Entity&#xff1a;只是一个代表&#xff0c;用于快速查找数…

前端Vue基于腾讯地图Api实现的选择位置组件 返回地址名称详细地址经纬度信息

前端Vue基于腾讯地图Api实现的选择位置组件 返回地址名称详细地址经纬度信息&#xff0c; 下载完整代码请访问uni-app插件市场地址&#xff1a;https://ext.dcloud.net.cn/plugin?id13310 效果图如下&#xff1a; #### 使用方法 使用方法 <!-- leftTitle:左边标题 name&…

哈工大计算机网络课程网络层协议详解之:路由算法概述与链路状态路由算法

哈工大计算机网络课程网络层协议详解之&#xff1a;路由算法概述与链路状态路由算法 在前面的小节中&#xff0c;我们介绍了网络中路由器的路由与转发等功能。我们说作为网络层&#xff0c;从功能上来说&#xff0c;核心功能就是要实现路由和转发。 对于转发来说&#xff0c;实…

PyTorch开放神经网络交换(Open Neural Network Exchange)ONNX通用格式模型的熟悉

我们在深度学习中可以发现有很多不同格式的模型文件&#xff0c;比如不同的框架就有各自的文件格式&#xff1a;.model、.h5、.pb、.pkl、.pt、.pth等等&#xff0c;各自有标准就带来互通的不便&#xff0c;所以微软、Meta和亚马逊在内的合作伙伴社区一起搞一个ONNX(Open Neura…

Redis - 优惠券秒杀、库存超卖、分布式锁、Redisson

文章目录 一、优惠券秒杀1.1 全局唯一ID概述1.2 Redis实现全局唯一ID1.3 添加优惠券1.3.1 entity1.3.2 Controller1.3.3 Service层1.3.4 测试 1.4 优惠券秒杀下单1.4.1 entity1.4.2 Controller1.4.3 Service1.4.3 测试 1.5 库存超卖问题1.5.1 库存超卖原因1.5.2 介绍乐观锁1.5.…

【博学谷学习记录】超强总结,用心分享 | 架构师 Jenkins学习总结

文章目录 Jenkins介绍背景应用场景主从集群 Jenkins使用访问Jenkins获取管理员密码进入jenkins主页修改管理员密码 安装插件插件安装 全局工具配置 企业实战pipeline(重点)创建PipelinePipeline语法语法示例 Jenkins介绍 背景 ​ Jenkins&#xff0c;之前叫做Hudson&#xff…

php开发人员信息搜索查询系统 名单查询系统后台 php增删改查功能

php实现人员信息搜索的功能的方法&#xff1a;1、创建conn.php文件连接人员信息数据库&#xff1b;2、创建index.php文件&#xff1b;3、通过“ if(isset($_POST[“flag”])){…}”等语句实现人员搜索功能即可。 1、首次登录需要输入访问的密码 <?php /*** 登录 **/ $mo…

git的基础总结

写在前面&#xff1a; 前天搞了个面试&#xff0c;发现好多都是会使用&#xff0c;但是要我说&#xff0c;难得说出来&#xff0c;现在对基础进行巩固总结。其实我感觉要求背出来一样的没必要吧&#xff0c;ide基本上可视化了会用就行吧。 文章目录 介绍git的状态 使用/安装/…

php使用PhpSpreadsheet导出Excel表格详解

本文会介绍php使用PhpSpreadsheet操作Excel&#xff0c;供大家参考&#xff0c;具体内容如下&#xff1a; PhpSpreadsheet介绍 1、简介 PhpSpreadsheet 是一个用纯PHP编写的库&#xff0c;提供了一组类&#xff0c;使您可以读取和写入不同的电子表格文件格式 PhpSpreadsheet …