javascript数据结构与算法----哈希表扩容

(1)为什么需要扩容?
因为常用的链地址法,loadFactor可以大于1,所以此时设计的哈希表可以无限的插入数据,但是随着数据量的增加,每一个index对应的bucket会越来越长,也就是造成了效率的降低。所以在适当的情况下需要对数组进行扩容,比如2倍。
(2)如何进行扩容?
可以简单的将之前的容量扩大两倍,但是在这种情况下,所有的数据项一定要同事修改(重新调用哈希函数,获取不同的位置),比如hashCode为12的数据项的时候,在length为8的时候,index=5,在长度为16的时候,index=12。这是一个耗时的过程,但是如果数组需要扩容,那么这个过程是必要的。
(3)什么情况进行扩容?
当loadFactor>0.75的时候,比如加吧的哈希表家室在填充因子大于0.75的时候就对哈希表进行扩容。
(4)哈希表扩容的代码实现

HashTable.prototype.resize=function(newlimit){
    // 先保存就得数据
    var oldStorage = this.storage
    // 重置属性
    this.storage = []
    this.count = 0
    this.limit = newlimit

    // 遍历
    for(var i =0;i<oldStorage.length;i++){
        var bucket = oldStorage[i]
        if(!bucket){
            continue
        }else{
            for(var j=0;j<bucket.length;j++){
                var tuple = bucket[i]
                this.put(tuple[0],tuple[1])
            }
        }
    }
}

在元素进行插入的时候,需要进行判断是否需要进行扩容操作

if(this.count >  this.limit * 0.75){
    this.resize(this.limit * 2)
}


// 优化原本的put的实现
    HashTable.prototype.put=function(key,value){
       // 1.根据key获取index
       var index = this.hashFunc(key,this.limit)

       // 根据index取出对应的桶
       var bucket = this.storage[index]
       // 如果对应的位置没有桶那么就进行新创建
       if(!bucket){
         bucket = []
         this.storage[index] = bucket
       }
       // 判断是否是修改数据
       for(var i=0;i<bucket.length;i++){
         var tuple = bucket[i]  //此时bucket的每一个元素也是数组的形式
         if(tuple[0] == key){
           tuple[1] = value
           return 
         }
       }

       // 进行添加
       bucket.push([key,value])
       this.count += 1

       if(this.count >  this.limit * 0.75){
           this.resize(this.limit * 2)
       }
     }

(4)哈希表缩容,在删除操作的时候,

if(this.limit >7 && this.count < this.limit * 0.25 ){
    this.resize(Math.floor(this.limit/2))
}

优化原本的删除操作

HashTable.prototype.remove=function(key){
    var index = this.hashFunc(key,this.limit)
    var bucket = this.storage[index]
    if(!bucket){
        return null
    }else{
        for(var i=0;i<bucket.length;i++){
            var tuple = bucket[i]
            if(tuple[0] == key){
                // 从bucket数组中删除当前元素i
                bucket.splice(i,1)
                // 总数减少
                this.count--
                // 缩容
                if(this.limit >7 && this.count < this.limit * 0.25 ){
                    this.resize(Math.floor(this.limit/2))
                }
                // 返回当前删除的元素
                return tuple[1]
            }
        }
        return null
    }
}

对扩容进行优化,判断扩容之后是不是一个质数,如果不是质数的话,就需要寻找一个接近于2 被的质数,将这个新的质数作为新的容量。
面试题:如何判断一个数是不是质数?
第一种实现:通过循环,但是效率不是很高。

 function judeNum(num){
   if(typeof num != 'number'){
     return '请输入一个数字'
   }else{
     // 循环输出
     for(var i=2;i<num;i++){
       if(num % i == 0) return `${num}不是质数`
     }
     return `${num}是质数`
   }
 }

第二种实现:
如果一个数字能够被分解,那么它分解的因子一个会大于等于它本身的开平方根,一个小于等于它本身的开平方根。

function judeNum2(num){
  if(typeof num != 'number'){
    return '请输入一个数字'
  }else{
    var temp = parseInt(Math.sqrt(num))
    for(var i=2;i<=temp;i++){
      if(num % i == 0) return `${num}不是质数`
    }
    return `${num}是质数`
  }
}

如何岁哈希表的扩容进行优化?

  // 判断当前传入数字是否是质数
  HashTable.prototype.isPrime=function(num){
    var temp = parseInt(Math.sqrt(num))
    for(var i=2;i<=temp;i++){
      if(num % i == 0) return false
    }
    return true
  }
  // 获取质数的方法
  HashTable.prototype.getPrime=function(num){
    while(!this.isPrime(num)){
      num ++
    }
    return num
  }

getPrime函数的调用是在改变数组容量的地方,即是元素添加和操作删除的地方,优化原本的代码为

if(this.count > this.limit * 0.75){
  var newSize = this.getPrime(this.limit * 2)
  this.resize(newSize)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值