我对JS散列表的简单学习

对JS散列表的简单学习

HashTable类也叫HashMap类,是Dictionary类的一种散列表实现方式。算法

散列算法的做用是尽量快的在数据结构中找到一个值。数据结构

在以前的学习中,若是你想要得到数据结构中的一个值,须要遍历整个数据结构来找到它。若是使用散列函数,就能知道具体位置,也就可以快速找到该值。app

使用最多见的散列函数--‘lose lose’散列函数,简单的将每一个键值中的每一个字母的ASCII码值相加,将获得的散列值做为地址。函数

(键值)John (散列函数)74+111+104+110 (散列值)399 造成散列表学习

地址 数据键值对
[399] john/john@email.com
...
[685] gandalf/@email.com

相关操做方法

建立一个散列表this

function HashTable() {
  var table = [];
}

实现一个散列函数,即将ASCII码值相加的方法。指针

var loseloseHashTable = function(key) {
  var hash = 0;
  for(var i = 0; i < key.length; i++) {
    hash += key.charCodeAt(i);
  }
  return hash % 37; //这里只是为了获得比较小的数值,随便除了一个数
}

实现put(key, value)方法,向散列表中添加一个新的项。code

this.put = function (key, value) {
  var position = loseloseHashTable(key); //获得散列值,即位置
  table[position] = value;
};

实现get(key)方法,返回根据键值检索到的特定的值。索引

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

实现remove()方法,从散列中移除键值对应的数据值。ip

this.remove = function(key) {
  table[loseloseHashTable(key)] = undefined; //没有数据占据的位置默认值为undefined
};

具体使用方法这里就不赘述了,就是方法的调用。

冲突怎么办?

假若有多个键值获得的散列值相等,那么后面的元素会覆盖前面前面相同散列值的元素,
怎么解决呢?

  • 分离连接

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

地址 链表存储数据
[5] [no1/no1.com]指针-> [no2/no2.com]指针-> [X]null

在地址5上,链表实例上有两个元素no1.com和no2.com。

须要添加一个valuePair类,来表示将要加入链表的实例的元素。

var valuePair = function(key, value) {
  this.key = key;
  this.value = value;
  this.toString = function() {
    return `[${this.key} - ${this.value}]`;
  }
}

重写一个put()方法

this.put = function(key, value) {
  var position = loseloseHashTable(key);
  if(table[position] == undefined) {
    table[position] = new LinkedList(); //若是这个位置是第一次被加入元素,那么就初始化一个LinkedList实例
  }
  table[position].append(new valuePair(key, value)); //链表实现的append方法添加一个valuePair实例。
};

重写一个get(key)方法

this.get = function(key) {
  var position = loseloseHashTable(key);
  if(table[position] !== undefined) { //位置上有元素存在
    //遍历链表来寻找键/值
    var current = table[position].getHead();
    while (current.next) { //这里遍历不到链表最后一个位置
      if(current.element.key === key) {
        return current.element.value; //element属性是valuePair的实例,包含key和value属性
      }
      current = current.next;
    }

    //检查元素在链表第一个或者最后一个的状况
    if(current.element.key === key) {
      return current.element.value;
    }
  }
  return undefined; //位置上没有值
};

重写remove(key)方法

this.remove = function(key) {
  var position = loseloseHashTable(key);

  if(table[position] !== undefined) {
    var current = table[position].getHead();
    while (current.next) {
      if(current.element.key === key) {
        table[position].remove(current.element); //链表实现的remove方法
        if(table[position].isEmpty()) { //删除元素以后判断链表是否变空
          table[position] = undefined;
        }
        return true;
      }
      current = current.next;
    }

    //检查是不是第一个或者最后一个元素
    if(current.element.key === key) {
      table[position].remove(current.element);
      if(table[position].isEmpty()) {
        table[position] = undefined;
      }
      return true;
    }
  }
  return false;
}
  • 线性探查

若是索引为index的位置已经被占据了,就尝试index+1的位置,以此类推。

5的位置被占据,就寻找6的位置,6的位置被占据,就找7,7没被占据就赋值(本应该在位置5上,可是线性探查变成了位置7)

实现put(key, value)方法

this.put = function(key, value) {
  var position = loseloseHashTable(key);
  if(table[position] === undefined) { //这个位置没有被占据
    table[position] = new valuePair(key, value);
  } else {
    var index = ++position; //寻找下一个位置
    while(table[index] !== undefined) { //被占据继续寻找下一个位置
      index ++;
    }
    table[index] = new valuePair(key, value);
  }
};

实现get()方法

this.get = function(key) {
  var position = loseloseHashTable(key);
  if(table[position] !== undefined) {
    if(table[position].key === key) { //举例位置5
      return table[position].value; //记号1
    } else {
      var index = ++position;
      while(table[index] !== undefined && (table[index] && table[index].key !== key)) { //该位置有元素可是不是要寻找的元素
        index ++; //索引增长
      }
      if(table[index] && table[index].key === key) { //确认正确性
        return table[index].value; //找到7 //记号2
      }
    }
  }
  return undefined;
};

实现remove()方法

只须要改变get方法的记号1和记号2的位置代码便可
改成table[index] = undefined;

更好的散列函数

var djb2HashCode = function(key) {
  var hash = 5381; //初始化一个hash变量并赋值为一个质数5381
  for(var i = 0; i < key.length; i++) { //遍历
    hash = hash * 33 + key.charCodeAt(i);
  }
  return hash % 1013;
}

相比来讲,冲突会变少不少~

相关文章
相关标签/搜索