散列表--JavaScript

1.散列函数的作用:

尽可能快的在一个数据结构中找到一个值

2.常见的散列函数:

    loselose 函数:简单的将每个键值中的每个字母的ASII码相加,然后再对37取余

简单实现:

// 未解决hash冲突的hash表
var HashTable = function () {
    var items = [];
    this.has = function (key) {
        return key in items;
    },
    //获取元素的hash地址、
    this.loseloseHashCode = function (key) {
        var hash = 0,
        i = 0;
        for(;i< key.length;i++){
            hash += key[i].charCodeAt();
        }
        return hash%37;
    },
    //加入元素
    this.put = function (key,value) {
        var position = this.loseloseHashCode(key);
        if(!this.has(key)){
            items[position] = value;
            return true;
        }
        return false;
    },
    //获得元素
    this.get = function (key) {
        var position = this.loseloseHashCode(key);
        return items[position];
    },
    this.values = function () {
        return items;
    }
    this.clear = function () {
        items = [];
    }
}

2.1.解决哈希冲突

哈希冲突不同的值再散列表中对应相同的位置

2.1.1分离链接解决哈希冲突

思想:它为在散列表相同位置的元素创建一个链表,将元素存储在里面,因此还需要一个辅助的数据结构---链表

代码实现:

//分离链接解决hash冲突
   /*
   * 分离链接法主要思想:将hash冲突的数据用链表链接起来
   * */
   //链表结构:
   var LinkList = function () {
       var items = [];
       var Node = function (element) {
           this.element = element;
           this.next = null;
       };
       var length = 0;
       var head = null;
       this.append = function (element) {
           var node = new Node(element),
           cur = head;
           if(cur === null){
               head = node;
           }else{
               while(cur.next!= null){
                   cur=cur.next;
               }
               cur.next = node;
           }
           length++;
       },
           //删除某个位置下的元素,下标从1开始
           this.removeAt = function (position) {
               var cur = head,
               pre=null,
               index = 1;
               if(position ===1){
                   head = cur.next;
                   length--;
                   return cur.element;
               }
               if(position>1&&position<length){
                   while(index < position&&cur.next!=null){
                       pre = cur;
                       cur = cur.next;
                       index++;
                   }
                   pre.next = cur.next;
                   length--;
                   return cur.element;
               }
               return false;
           },
           this.remove = function (element) {
               return this.removeAt(this.indexOf(element));
           },
           this.insert = function (element,position) {
               var index = 0,
                   cur = head,
                   pre = null,
                   node = new Node(element);
               if(position ===1){
                   head = node;
                   head.next = cur;
                   length++;
                   return true;
               }
               if(position>1 && position<=length){
                   while(cur.next!=null&&index<=position){
                       pre = cur;
                       cur = cur.next;
                       index++;
                   }
                   pre.next = node;
                   node.next =cur;
                   length++;
                   return true;
               }
               return false;
           },
       this.indexOf = function (elememt) {
           var cur = head,
           index = 1;
           while(cur.next!=null){
               if(cur.element === elememt){
                   return index;
               }
               index++;
               cur=cur.next;
           }
           return index;
       },
       this.getHead = function () {
           return head;
       },
       this.size = function () {
           return length;
       },
       this.isEmpty = function () {
           return items.length?true:false;
       }
   };
   var HashTable_L = function () {
       var tables = [];
       var Node1 = function (key,val) {
           this.key = key;
           this.val = val;
       };
       //找到元素的hash地址
       this.loseloseHashCode = function (key) {
           var hash = 0,
               i = 0,
               l = key.length;
           for(; i< l; i++){
               hash += key[i].charCodeAt();
           }
           return hash%37;
       }
       this.has = function (key) {
           return key in tables;
       }
       //放入元素
       this.put = function (key,val) {
           var position = this.loseloseHashCode(key);
           if(tables[position] === undefined){
               tables[position] = new LinkList();
           }
           tables[position].append(new Node1(key,val));
           // console.log(tables[position].getHead());
       }
           //获取元素
       this.get =function (key) {
           var position = this.loseloseHashCode(key);
           if (tables[position] !== undefined){
               var cur = tables[position].getHead();
               while (cur.next!=null) {
                   if (cur.element.key === key){
                       return cur.element.val;
                   }
                   cur = cur.next;
               }
               //对于第一项和最后一项的判断
               if (cur.element.key === key){
                   return cur.element.val;
               }
           }
           return false;
       }
           //删除元素
       this.remove = function (key) {
           var position = this.loseloseHashCode(key);
           if(tables[position]!==undefined){
              var cur = tables[position].getHead();
              while (cur.next!=null){
                  if(cur.element.key === key){
                      tables[position].remove(cur.element);
                       if(tables[position].isEmpty()){
                           tables[position] = undefined;
                       }
                       return true;
                  }
                  cur = cur.next;
              }

              //判断最后一个和第一个元素
              if(cur.element.key === key){
                  tables[position].remove(cur.element);
                  return true;
              }
           }
           return false;
       }
       this.values = function () {
           return tables;
       }
   };

2.1.2线性探测法解决哈希冲突

主要思想:当想往散列表中加入一个元素时,如果该位置被占了就放入它的下一个位置,如果它的下一个位置也被占了,就放入下下一个。

代码实现:

//线性探查法解决hash冲突
 var HashTable_X = function () {
     //数据的存储结构
      var Node = function (key,val) {
          this.key = key;
          this.val = val;
          this.toString = function () {
              return this.key+',  '+this.val;
          }
      }
      var tables = [];//线性表;
     this.loseloseHashCode = function (key) {
         var hash = 0,
             i = 0,
             l = key.length;
         for(; i<l; i++){
             hash += key[i].charCodeAt();
         }
         return hash%37;
     }
     //put方法
     this.put = function (key,val) {
         var position = this.loseloseHashCode(key);
         console.log('为解决冲突的hash地址',position);
         // if(tables[position] === undefined){
         //     tables[position] = new Node(key,val);
         // }else{
         //     while(tables[position] !== undefined){
         //         position++;
         //     }
         //     tables[position] = new Node(key,val);
         // }
         if(tables[position] !== undefined){
             while(tables[position]!==undefined){
                 position++;
             }
         }
         console.log(key,position);
         tables[position] = new Node(key,val);
     }
     //get方法思想:首先找到需要查询元素的位置,通过比较key,然后返回查找的元素的val
     this.get = function (key) {
         var position = this.loseloseHashCode(key);
         if(tables[position]!== undefined){
             if(tables[position].key === key){
                 return tables[position].val;
             }else {
                 var index = ++position;

                 while(tables[index].key!==key || tables[index]===undefined){
                     index++;
                 }
                 if(tables[index].key === key){
                     return tables[index].val;
                 }
             }
         }
         return undefined;
     }
     //思想与get一样,只是找到之后将这个位置的元素设置为undefined
     this.remove = function (key) {
         var position = this.loseloseHashCode(key);
         if(tables[position]!== undefined){
             if(tables[position].key === key){
                 tables[position] = undefined;
             }else{
                 var index = ++position;
                 while(tables[index].key !== key || tables[index] === undefined){
                     index++;
                 }
                 if(tables[index].key === key){
                     tables[index] = undefined;
                 }
             }
         }
     }
     this.values = function () {
         return tables;
     }
 }

3.djb2HashCode解决哈希冲突

djb2:一个简单产生简单随机分布的哈希函数

1.为什么选择33:
    1)乘法易于移位或相加
    2) 从移位和加法实现中可以看到,使用33可以复制散列累加器中的大多数输入位,
    然后将这些位相对地分散开来。这有助于形成好的雪崩现象。使用较大的移位将复制更少的位,
    使用较小的移位将使位交互更局部,并使交互扩展所需的时间更长。
    3) 32 = 2^5,32 与移 5 位相关,有助于将每一个字符串的每一位比特都作用到最终的哈希值当中
    4) 在考虑ASCII字符数据时,5的移位是一个很好的移位量。ASCII字符可以看作是4位字符类型选择器和4位字符
    类型选择器。前4位的数字都是0x3。因此,8位移位将导致具有特定含义的位与具有相同含义的其他位相互作用。
    4位或2位的移位同样会在相似的位之间产生强烈的交互作用。5位的移位使得一个字符的4个低阶位中的许多位与
    同一字符的4个上位中的许多强相互作用
选择5381并不太重要,很多其他的大的质数数也可以运行地很好。

代码实现:

var HashTable = function () {
    var tables = [];
    this.has = function (key) {
        return key in tables;
    }
    this.djb2HashCode =function (key) {
        var hash = 5381,//选择5381并不太重要,很多其他的大的质数数也可以运行地很好。
        i = 0,
        l = key.length;
        for(;i<l;i++){
            hash = hash*33+key[i].charCodeAt();
        }
        return hash%1013;
    }
    this.put = function (key,val) {
        var position = this.djb2HashCode(key);
        tables[position] = val;
    }
    this.remove = function (key) {
        var position = this.djb2HashCode(key);
        tables[position] = undefined;
    }
    this.get = function (key) {
        var position = this.djb2HashCode(key);
        return tables[position];
    }
    this.values = function () {
        return tables;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值