使用散列表的查找算法分为两步:
1. 散列函数将被查找的键转化为数组的一个索引。
2. 处理碰撞冲突(拉链法和线性探测法)
散列函数
- 整数, 除数留余法:选择大小为素数M的数组,对于任一正整数k,计算k除以M的余数。
- 浮点,如果键是0到1之间的实数,我们可以将它乘以M并四舍五入得到一个0至M-1之间的索引值。
- 字符串, 除数留余
基于拉链法的散列表
class SeperateChainingHashST {
constructor (M) {
this.N = 0;//键值对总数
this.M = M;//散列表大小
this.st = [];
for (let i = 0; i < M; i++){
this.st[i] = new SequentialSearchST();
}
}
hash (key) {
return key%this.M;
}
put (key, value) {
this.N++;
this.st[this.hash(key)].put(key, value);
}
get (key) {
return this.st[this.hash(key)].get(key);
}
}
//顺序查找链表
class Node {
constructor (key, value, next) {
this.key = key;
this.value = value;
this.next = next;
}
}
class SequentialSearchST {
constructor () {
this.first = null;
}
get (key) {
let temp = this.first;
while(temp && temp.key !== key) {
temp = temp.next;
}
return temp && temp.value;
}
put (key, value){
let temp = this.first;
let prev =null;
while(temp && temp.key !== key){
prev = temp;
temp = temp.next;
}
if(value !== undefined && temp == null ) {
this.first = new Node(key, value, this.first);
return;
}
if(value == undefined){
if(prev === null){
this.first =this.first && this.first.next;
} else {
prev.next = temp && temp.next;
}
}else{
temp.value = value;
}
}
}
基于线性探测法的散列表
开放寻址类的散列表的核心思想是将散列表的空元素当做查找结束的标志。
class LinearProbingHashST {
constructor (M) {
this.N = 0;
this.M = M;
this.keys = [];
this.value = [];
}
hash (key) {
return key%this.M;
}
put (key, value) {
if(this.N >= this.M/2) this.resize(2 * this.M);
let i;
for(i = this.hash(key); this.keys[i] != undefined; i = (i + 1)%this.M ) {
if(this.keys[i] === key){
this.value[i] = value;
return ;
}
}
this.N++;
this.keys[i] = key;
this.value[i] = value;
}
get (key) {
for(i = this.hash(key); this.keys[i] != undefined; i = (i + 1)%this.M ) {
if(this.keys[i] === key){
return this.value[i];
}
}
return null;
}
delete (key) {
if(this.get(key) === null) return;
let i = key%this.M;
while(this.keys[i] != key){
i = (i+1)%this.M;
}
this.keys[i] = null;
this.value[i] = null;
i = (i+1)%this.M;
while(this.keys[i] != null){
let newKey = this.keys[i];
let newValue = this.value[i];
this.keys[i] = null;
this.value[i] = null;
this.N--;
this.put(newKey, newValue);
i = (i+1)%this.M;
}
this.N--;
if(this.N > 0 && this.N <=Math.ceil(this.M/8)) this.resize(Math.ceil(this.M/2))
}
resize (M) {
this.M = M;
let oldKeys = this.keys;
let oldValue = this.value;
this.keys = [];
this.value = [];
this.N = 0;
for(let i in oldKeys) {
this.put(oldKeys[i], oldValue[i]);
}
}
}