Javascript常见数据结构四——集合、字典、哈希表

Javascript常见数据结构四——集合、字典、哈希表

五、集合

1.创建集合结构

集合是由一组无序且唯一的数据组成

ES6 Set 结构就是集合,接下来我们基于Set数据结构进行讨论

功能需求分析:

add 新增集合元素
has 判断该元素是否存在于该集合
delete 删除指定集合元素
size 返回集合长度
clear 清空集合
let Set = (function (){
       let symbol = Symbol()
        return class {
            constructor(arr) {
                this[symbol] = []
                if(Array.isArray(arr)){
                    arr.forEach(item=>{
                        if(!this[symbol].includes(item)){
                            this[symbol].push(item)
                        }
                    })
                }
            }
            add(data){
                if(!this[symbol].includes(data)){
                    this[symbol].push(data)
                }
            }
            has(data){
                return this[symbol].includes(data)
            }
            delete(data){
                let index = this[symbol].indexOf(data)
                if(index===-1)return
                this[symbol].splice(index,1)
            }
            size(){
                return this[symbol].length
            }
            clear(){
                this[symbol]=[]
            }
        }
    })()

2.并集、交集、差集、子集

并集 -- 将两个集合合并
 function union(a,b){
        return new Set([...a,...b])
    }
// 交集 -- 找到两个集合相交的地方
function intersection(a,b){
    let set = new Set()
    for (const aElement of a) {
        if(b.has(aElement)){
              set.add(aElement)
        }
    }
    return set
}
// 差集 找到两个集合不相交的数据
// a-b 顺序是有影响的 是用第二个数据去排除第一个数据里拥有的数据
function difference(a,b){
    let set = new Set()
    for (const aElement of a) {
        if(!b.has(aElement)){
            set.add(aElement)
        }
    }
    return set
}
// 子集 -- 检测 b是不是 a 的子集
function subset(a,b){
    for (const x of b) {
        if(!a.has(x)){
            return false
        }
    }
    return true
}

六、字典

1.创建字典结构

字典是一种以(键值)的形式存储数据的数据结构,键用来查找对应的值,就像字典里面的每个字(键)都有对应的有他的解释(值),再比如电话簿,名字(键)对应电话(值)。

ES6 Map 数据结构就是一种字典

字典中的键可以是任意的数据类型

功能需求分析

设置数据 set
获取数据 get
删除数据 delete
是否存在 has
返回长度 size
// js对象
本身是不允许对象作为键值的 只允许 数字 字符串
所有的非字符串数字的 的 键值 会被强制转化为字符串
对象被转为字符串 [object Object]
// map 
只要两个对象不是同一个 都可以 进行分开存储
map 存值的前提是 两个值不一样
原始值  键名相同的原始值  都会被覆盖
引用值  只要不是同一个地址 就不会存在覆盖的问题
如果参数是一个对象 直接返回undefined 因为 参数的引用是独立的
console.log(map.get({x:10}));// undefined
let Map = (function () {
    const symbol = Symbol()
    return class {
        constructor() {
            this[symbol] = []
        }
        // 清空字典
        clear(){
            this[symbol] = []
        }

        // 字典中删除某个数据
        delete(data){
            for (let i = 0, len = this[symbol].length; i < len; i++) {
                let thisData = this[symbol][i]
                let k = thisData[0]
                if (k === data) {
                   return this[symbol].splice(i,1)
                }
            }
        }

        // 检测某个数据在字典中是否存在
        has(data){
            for (let i = 0, len = this[symbol].length; i < len; i++) {
                let thisData = this[symbol][i]
                let k = thisData[0]
                if (k === data) {
                    return true
                }
            }
            return false
        }

        // 返回字典的长度
        size(){
            return this[symbol].length
        }

        // 设置某个属性
        set(key, value) {
            // 避免重复定义
            for (let i = 0, len = this[symbol].length; i < len; i++) {
                let thisData = this[symbol][i]
                let k = thisData[0]
                if (k === key) {
                    thisData[1] = value
                    return
                }
            }
            let arr = [key, value]
            this[symbol].push(arr)
        }

        // 获取某个属性
        get(key) {
            for (let i = 0, len = this[symbol].length; i < len; i++) {
                let thisData = this[symbol][i]
                let k = thisData[0]
                let v = thisData[1]
                if (k === key) {
                    return v
                }
            }
        }

        // 打印所有key值
        keys(){
            let arr = []
            this[symbol].forEach(([key,value])=>{
                arr.push(key)
            })
            return arr
        }

        // 打印所有values
        values(){
            let arr = []
            this[symbol].forEach(([key,value])=>{
                arr.push(value)
            })
            return arr
        }
    }
})()

七、哈希表

1.创建哈希表结构

哈希表也叫散列表 ,也是一种基于键值对存储值的一种数据结构

与数组的区别在于,哈希表能够快速的定位值得位置,而不需要逐个遍历匹配

js对象 就具有哈希表结构的特性

创建一个简单的哈希表数据类型:

let Hash = (function () {
        // 哈希函数
        function HASH(key) {
            // 通过算法 得到key值对应的下标值
            let code = 0;
            [...key].forEach(item => {
                code += item.charCodeAt(0)
            })
            return code
        }
        const symbol = Symbol
        return class {
            constructor() {
                this[symbol] = []
            }

            set(key,value) {
                let hashCode = HASH(key)
                console.log(hashCode)
                this[symbol][hashCode] = value
            }
            get(key){
                let hashCode = HASH(key)
                return this[symbol][hashCode]
            }
        }
    })()
当前哈希表存在两个明显的问题:
1.  数组太长 --- 数组利用率比较低 存了几个数据开辟了几百个空间
2.  下标重复率高  --- 哈希函数不合理

这个时候需要我们解决当前这两个比较严重的问题,此时 ,我做了如下修改

// 解决空间利用率低的问题  和 下标重复率高的问题
let Hash = (function () {
    // 哈希函数
    function HASH(key) {
        // 通过算法 得到key值对应的下标值
        let code = 0;
        [...key].forEach(item => {
            code += item.charCodeAt(0)
        })
        // 解决数组利用率过大问题
        // 使用除法和减法效果都不好
        // 可以采用求模运算 最好是质数
        return code % 13
     }

    const symbol = Symbol
    return class {
        constructor() {
            this[symbol] = []
        }

        set(key, value) {
            let hashCode = HASH(key)
            // let i = 1
            // 进行线性向下探索存储
            while (this[symbol][hashCode] !== undefined) {
                // 说明已经存在对应的hash
                hashCode = (hashCode + 1) % 13
                // 以下情况适用于范围比较大的线性探索
                /*hashCode += i **2
                i++*/
            }
            this[symbol][hashCode] = [key,value]
        }

        get(key) {
            let hashCode = HASH(key)
            // 不存在对应的code
            if(!this[symbol][hashCode]){
                return undefined
            }

            // 存在就判断对应的key值等不等于 不等于 就继续探索
            while(this[symbol][hashCode][0]!==key){
                hashCode = (hashCode + 1) %13
                // 如果 hash对应的数据 不存在
                if(!this[symbol][hashCode]){
                    return undefined
                }
            }
            return this[symbol][hashCode]
        }
    }
})()
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

貂蝉的腿毛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值