当前位置: 首页 > news >正文

《Javascript数据结构和算法》笔记-「字典和散列表」

《Javascript数据结构和算法》笔记-「字典和散列表」

集合、字典、散列表存储的都是「不重复」的数据结构

  • 集合:我们更关注每一个元素的值,并把其作为主要元素
  • 字典:我们用[键,值]的形式来存储数据
  • 散列表: 跟字典类似,也会是用[键,值]的形式来存储数据

但是「字典」和「散列表」的实现方式略有不同。

字典

字典也称作映射。我觉得这种数据结构,其实在业务代码中的应用很常见。

与Set类似,ES6同样实现了一个Map类,即我们所说的字典

字典的大致骨架

    function Dictionary(){
        var items = {}
    }

    this.set = function(key,value){}
    this.get = function(key){}
    this.delete = function(key){}
    this.has = function(key){}
    this.clear = function(){}
    this.size = function(){}
    this.keys = function(){}  // 将字典所包含的所有键,以一个数组返回
    this.values = function(){}  // 将字典所包含的所有值,以一个数组返回

字典类的实现,十分简单就直接粘贴全部代码了。

我觉得在JS中,对象本身就可以作为字典来使用。我经常在业务代码中把数据处理成这种字典的数据结构

        function Dictionary() {
            var items = {}

            this.has = function ( key ) {
                return items.hasOwnProperty( key )
            }

            this.set = function ( key, value ) {
                items[ key ] = value
            }

            this.delete = function ( key ) {
                if ( this.has( key ) ) {
                    delete items[ key ]
                    return true
                }
                return false
            }

            this.get = function ( key ) {
                if ( this.has( key ) ) {
                    return items[ key ]
                } else {
                    return undefined
                }
            }

            this.values = function(){
                return Object.values(items)
            }

            this.keys = function(){
                return Object.keys(items)
            }

            this.clear = function(){
                this.items = {}
            }

            this.size = function(){
                return this.keys().length
            }

            this.getItems = function(){   // 获取items的方法
                return items
            }
        }

        var dictionary = new Dictionary()

        dictionary.set('Gandalf','gandalf@email.com')
        dictionary.set('John','johnsnow@email.com')
        dictionary.set('Tyrion','tyrion@email.com')

        console.log(dictionary.has('Gandalf'))
        console.log(dictionary.size())
        console.log(dictionary.keys())
        console.log(dictionary.values())
        console.log(dictionary.get('Tyrion'))
        dictionary.delete('John')
        console.log(dictionary.keys())
        console.log(dictionary.values())
        console.log(dictionary.getItems())

哈希表

在学习了Dictionary类之后,我们会学习散列表,也就是哈希表。它是Dictionary类的另外一种实现方式

我在读到这里时,对于「字典」和「哈希表」2个慨念之间的区别还没弄清,当然书中也没有太多解释。

所以这里,我写记录一下自己查阅资料后的个人理解

「字典」指的是Key-Value这种存储数据的结构

那么哈希表也是字典,但是它是用另外的一种实现方式来做的。

那么我们我为什么要使用这种方式来实现「字典」呢,是不是字典存在某种缺点呢?

是的,比如说这样的一组字典数据

k1, k2, k3, k4, k4 ....
v1, v2, v3, v4, v5 ....

当你输入key,命令电脑查询key对应的value时,电脑其实是没法立刻找到key所对应的value呢

看上去是直接根据key得到value,但实际上电脑还是需要遍历k1、k2、k3去比较kn是否等于key。如果是的话就取出对应的值

那么为了省去这个遍历的过程,才想到用哈希表来实现「字典」

哈希表利用数组实现「字典」这种数据结构,那么用数组来实现字典的话,用户传入的key对应哪个索引呢?所以我们需要一个「散列算法」

「散列算法」,可以求出这个key在数组里对应的位置,用哈希表实现的目的就是尽可能快地在字典中找到一个值。


function HashTable(){
    let table = []

    // 散列算法
    var loseloseHashCode = function(key){
        var hash = 0;
        for(var i = 0 ; i<key.length ; i++){
            hash += key.charCodeAt(i)
        }
        return hash % 37   // 这里37是个随意选择的数值,把余数作为将来存储在数组的索引
    }
    this.put = function(key,value){
        var position = loseloseHashCode(key)
        console.log(position + '-' + key)
        table[position] = value
    }

    this.get = function(key){
        var position = loseloseHashCode(key)
        return table[position]
    }

    this.remove = function(key){
        var position = loseloseHashCode(key)
        table[position] = undefined
    }
}

哈希表的key值冲突

我们哈希表的散列算法,是为求出用户传入的key所对应的一个索引

那么这个索引是有可能重复的,一旦重复就会导致后面的值覆盖前面的值。

这种情况,叫做哈希表的冲突。所以我们了解2种处理冲突的方法原理

  • 分离链接: 把数组的每一个元素都实例成链表结构。这样key相同的值,也可以用单链表的形式不断存储。不会覆盖
  • 线性探查: 当用散列算法求出的这个索引index重复时,就index++,直到index不重复为止。

实现更好的散列函数

之前实现的'lose lose'散列函数,用来求值其实是非常容易产生key冲突的。

如果经常冲突的话,那么插入和查询一个元素的时间就会变慢(性能变差)

所以一个优秀的散列算法,应该是可以尽可能少出现冲突的

这里给出一个比较好的社区的实现。至于为什么这种算法,可以减少冲突我也不太理解,

可能是hash是质数,然后质数*33,最后在跟1013取模的话,不太会产生一样的余数,这个感觉是数学问题。

var djb2HashCode = function(key){
    var hash = 5381

    for(var i = 0 ; i < key.length ; i++){
        hash = hash*33 + key.charCodeAt(i)
    }

    return hash % 1013
}

简单回顾一下,集合、字典、哈希表吧

首先他们的元素都是不重复的

  • 集合: 是无序的,[value value]的形式的一组数据结构
  • 字典: 是由一对对 [key-value] 组成的数据结构
  • 哈希表: 是字典的另外一种实现方式,优点在于可能更快的根据key取到value

记录一下书中没搞清楚的小疑问:

《javascript数据结构和算法》中多次提到「顺序数据结构」和「非顺序数据结构」的慨念,并表示

- 「顺序数据结构」:栈、队列、数组、链表、集合
- 「非顺序数据结构」: 散列表 、 树

可是我觉得链表、集合是无序的,数组是有序的呀

这个「顺序数据结构」似乎并不是指的在内存中存储形式。问题先记下,回头再查把

相关文章:

  • unit 7文档练习
  • 进入Linux救援(rescue)模式的四大法门
  • Android开发12——Andorid中操作数据库的insert的两种方法以及nullColumnHack
  • 黑客系列-以彼之道还施彼身
  • [web前端] yarn和npm命令使用
  • 在windows上搭建镜像yum站的方法(附bat脚本)
  • 动手做个聊天室,前端工程师百无聊赖的人生
  • Price Tag | INTERVIEW 03 | 独立开发者 Tolecen
  • GitHub上优秀的Go开源项目
  • 51CTO试一下
  • 《从零开始学Swift》学习笔记(Day 10)——运算符是“ +、-、*、/ ”吗?
  • 从7个骨架项目启动你的rails开发
  • 宿主机为linux、windows分别实现VMware三种方式上网
  • DELPHI存储过程调用
  • Java集合源码分析之LinkedList
  • 【css3】浏览器内核及其兼容性
  • Angular数据绑定机制
  • C学习-枚举(九)
  • docker容器内的网络抓包
  • httpie使用详解
  • JavaScript实现分页效果
  • Java比较器对数组,集合排序
  • Laravel核心解读--Facades
  • Redis 中的布隆过滤器
  • Redis学习笔记 - pipline(流水线、管道)
  • WePY 在小程序性能调优上做出的探究
  • 初识MongoDB分片
  • 分享一份非常强势的Android面试题
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 通过git安装npm私有模块
  • 为什么要用IPython/Jupyter?
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • #Z0458. 树的中心2
  • #我与Java虚拟机的故事#连载04:一本让自己没面子的书
  • (C语言)fgets与fputs函数详解
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (poj1.3.2)1791(构造法模拟)
  • (附源码)springboot课程在线考试系统 毕业设计 655127
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (南京观海微电子)——COF介绍
  • (转)程序员技术练级攻略
  • (转)甲方乙方——赵民谈找工作
  • (转)项目管理杂谈-我所期望的新人
  • (最优化理论与方法)第二章最优化所需基础知识-第三节:重要凸集举例
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .net framework profiles /.net framework 配置
  • .net MVC中使用angularJs刷新页面数据列表
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .NET 简介:跨平台、开源、高性能的开发平台
  • .NET多线程执行函数
  • .pyc文件还原.py文件_Python什么情况下会生成pyc文件?
  • [17]JAVAEE-HTTP协议
  • [Android] 修改设备访问权限
  • [C/C++] -- 二叉树