最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScript数据结构(六)散列表

    正文概述 掘金(优岚)   2021-07-13   581

    1. 定义

    HashTable、HashMap,是Dictionary类的一种散列表实现方式

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

    散列函数:给定一个键值,然后返回值在表中的地址

    JavaScript数据结构(六)散列表

    2. 具体操作

    创建

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

    创建散列函数

    loseloseHashCode(key) {
        if(typeof key === 'number') {
            return key;
        }
        const tableKey = this.toStrFn(key);
        let hash = 0;
        for (let i = 0; i < tableKey.length; i++) {
            has += tableKey.charCodeAt(i);  //转换为ASII码值
        }
        return hash % 37;  //规避操作数超过数值变量最大表示范围的风险
    }
    
    hashCode(key) {
        return this.loseloeseHashCode(key);
    }
    

    方法

    • put(key,value):向散列表增加一个新的项(也能更新散列表)

      put(key, value) {
          if(key != null && value ! null) {
              const position = this.hashCode(key);
              this.table[position] = new ValuePair(key, value);
              return true;
          }
          return false;
      }
      
    • remove(key):根据键值从散列表中移除值

      remove(key) {
          const hash = this.hashCode(key);
          const valuePair = this.table[hash];
          if(valuePair != null) {
              delete this.table[hash];
              return true;
          }
          return false;
      }
      
    • get(key):返回根据键值检索到的特定的值。

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

    3. 使用

    const hash = new HashTable();
    
    hash.put('Gandalf', 'gandalf@email.com');
    hash.put('John', 'johnsnow@email.com');
    hash.put('Tyrion', 'tyrion@email.com');
    
    console.log(hash.hashCode('Gandalf') + ' - Gandalf'); // 19 - Gandalf
    console.log(hash.hashCode('John') + ' - John');  // 29 - John
    console.log(hash.hashCode('Tyrion') + ' - Tyrion');  // 16 - Tyrion
    console.log(hash.get('Gandalf')); // gandalf@email.com
    console.log(hash.get('Loiane')); // undefined
    
    hash.remove('Gandalf');
    console.log(hash.get('Gandalf'));
    

    散列表和散列集合

    类似

    散列集合由一个集合构成,插入、移除或获取元素时,使用的是hashCode函数

    4. 处理散列表的冲突

    当键有相同的散列值时,不同的值在散列表中对应着相同的位置,后面添加的值会覆盖前面的,称为冲突。

    处理冲突的几种方法: 分离链接、线性探查和双散列法

    1. 分离链接

    解决冲突的最简单的方法

    分离链接法包括为散列表的每一个位置创建一个链表并将元素存储在里面

    JavaScript数据结构(六)散列表

    创建

    class HashTableSeparateChaining {
        constructor(toStrFn = defaultString) {
            this.toStrFn = toStrFn;2
            this.table = {};
        }
    }
    

    方法

    • put(key,value):向散列表增加一个新的项(也能更新散列表)

      put(key, value) {
          if(key != null && value != null) {
              const position = this.hashCode(key);
              if(this.table[position] == null) {
                  this.table[position] = new LinkedList();
              }
              this.table[position].push(new ValuePair(key, value));
              return true;
          }
          return false;
      }
      
    • remove(key):根据键值从散列表中移除值

      remove(key) {
          const position = this.hashCode(key);
          const linkedList = this.table[position];
          if (linkedList != null && !linkedList.isEmpty()) {
              let current = linkedList.getHead();
              while (current != null) {
                  if (current.element.key === key){
                      linkedList.remove(current.element);
                      if (linkedList.isEmpty()) {
                          delete this.table[position];
                      }
                      return true;
                  }
                  current = current.next;
              }
          }
          return false;
      }
      
    • get(key):返回根据键值检索到的特定的值

      get(key) {
          const position = this.hashCode(key);
          const linkedList = this.table[position];
          if(linkedList != null && !linkedList.isEmpty()) {
              let current = linkedList.getHead();
              while(current != null) {
                  if(current.element.key === key){
                      return current.element.value;
                  }
                  current = current.next;
              }
          }
          return undefined;
      }
      

    2. 线性探查

    将元素直接存储到表中

    当想向表中添加一个新元素的时候,如果索引为position的位置被占据,以此寻找position+1、position+2……直到有空的位置

    删除键值对

    1. 软删除: 使用特殊的值(标记)来表示键值对被删除,并不是真的删除

      JavaScript数据结构(六)散列表

    2. 检验是否有必要将一个或多个元素移动到之前的位置。当搜索一个键的时候,这种方法可以避免找到一个空位置

      JavaScript数据结构(六)散列表

    方法

    • put(key,value):向散列表增加一个新的项(也能更新散列表)

      put(key, value) {
          if(key != null && value != null){
              const position = this.hashCode(key);
              if(this.table[position] == null) {
                  this.table[position] = new ValuePair(key, value);
              } else {
                  let index = position + 1;
                  while(this.table[position] != null) {  //如果位置被占了,就找下一位
                      index++;
                  }
                  this.table[index] = new ValuePair(key, value);
              }
              return true;
          }
          return false;
      }
      
    • remove(key):根据键值从散列表中移除值

      remove(key) {
          const position = this.hashCode(key);
          if (this.table[position] != null) {
              if (this.table[position].key === key) {
                  delete this.table[position];
                  this.varifyRemoveSideEffect(key, position);
                  return true;
              }
              let index = position + 1;
              while (this.table[index] != null && this.table[index].key !== key) {
                  index++;
              }
              if (this.table[index] != null && this.table[index].key === key) {
                  delete this.table[index];
                  this.verifyRemoveSideEffect(key, index);
                  return true;
              }
          }
          return false;
      }
      
      verifyRemoveSideEffect(key, removedPosition) {
          const hash = this.hashCode(key); 
          let index = removedPosition + 1; 
          while (this.table[index] != null) {
              const posHash = this.hashCode(this.table[index].key);
              if (posHash <= hash || posHash <= removedPosition) { 
                  this.table[removedPosition] = this.table[index];
                  delete this.table[index];  removedPosition = index; 
              } 
              index++; 
          }
      }
      
    • get(key):返回根据键值检索到的特定的值

      get(key) {
          const position = this.hashCode(key);
          if(this.table[position] != null){
              if(this.table[position].key === key) {
                  return this.table[position].value;
              }
              let index = position + 1;
              while(this.table[index] != null && this.table[index].key !== key) {
                  index++;
              }
              if(this.table[index] != null && this.table[index].key === key) {
                  return this.table[position].value;
              }
          }
          return undefined;
      }
      

    5. ES2015Map类

    const map = new Map();
    map.set('Gandalf', 'gandalf@email.com');
    map.set('John', 'johnsnow@email.com');
    map.set('Tyrion', 'tyrion@email.com');
    console.log(map.has('Gandalf')); // true console.log(map.size);
    console.log(map.keys()); // 输出{"Gandalf", "John", "Tyrion"} 
    console.log(map.values()); // 输出{"gandalf@email.com", "johnsnow@email.com", "tyrion@email.com"}
    console.log(map.get('Tyrion')); // tyrion@email.com
    map.delete('John');
    

    6. ES2105 WeakMap类和WeakSet类

    除了Set和Map这两种新的数据结构,ES2015还增加了它们的弱化版本,WeakSet和WeakMap

    区别

    • WeakSet或WeakMap类没有entries、keys和values等方法
    • 只能用对象作为键

    创建和使用这两个类主要是为了性能,WeakSet和WeakMap是弱化的(用对象作为键),没有强引用的键。这使得JavaScript的垃圾回收器可以从中清除整个入口。

    必须用键才可以取出值。这些类没有entries、keys和values等迭代器方法,因此,除非你知道键,否则没有办法取出值。

     const map = new WeakMap();
    const ob1 = { name: 'Gandalf' }; 
    const ob2 = { name: 'John' };
    const ob3 = { name: 'Tyrion' };
    map.set(ob1, 'gandalf@email.com');
    map.set(ob2, 'johnsnow@email.com');
    map.set(ob3, 'tyrion@email.com');
    console.log(map.has(ob1)); 
    console.log(map.get(ob3)); // tyrion@email.com {4} map.delete(ob2);
    

    起源地下载网 » JavaScript数据结构(六)散列表

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元