我對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;
}

相比來講,衝突會變少不少~

相關文章
相關標籤/搜索