《学习javascript数据结构与算法》——第七章:字典和散列表
集合以[值,值]的形式存储元素,而字典和散列表以[键,值]的形式存储元素
一、字典
创建字典
function Dictionary() {
var items = {};
/*has(key)如果某个键值存在于这个字典中,则返回true*/
this.has = function(key) {
return key in items;
};
/*set(key, value)向字典添加新元素*/
this.set = function(key, value) {
items[key] = value;
};
/*remove(key)从字典中移除键值对应的数据*/
this.remove = function(key) {
if (this.has(key)) {
delete items[key];
return true;
}
return false;
};
/*get(key)通过键值查找特定的数值并返回*/
this.get = function(key) {
return this.has(key) ? items[key] : undefined;
};
/*values()将字典所包含的所有数值以数组的形式返回*/
this.values = function() {
var values = [];
for (var k in items) { //包含了对象原型中的属性
if (this.has(k)) { //过滤掉对象原型中的属性
values.push(items[k]);
}
}
return values;
};
/*clear(), size, keys, getItems*/
this.clear = function() {
items = {};
};
this.size = function() {
return Object.keys(items).length;
};
this.keys = function() {
return Object.keys(items); //Object.keys()返回一个包含对象所有属性的数组
};
this.getItems = function() {
return items;
};
}
二、散列表
不是遍历键值来找到匹配的值,而是将每个属性转化为一个索引,通过数组的形式,检索到想要的值
创建散列表
先创建一个散列函数:给定key参数,就能够根据组成key的每个字符的ASCII码值的和得到一个数字
function HashTable() {
var table = [];
/*散列函数*/
var loseloseHashCode = function(key) {
var hash = 0;
for (var i = 0; i < key.length; i++) {
hash += key.charCodeAt(i);
}
return hash % 37;
};
/*添加、获取和移除等方法*/
this.put = function(key, value) {
var position = loseloseHashCode(key);
console.log(position + '-' + key); //可移除
table[position] = value;
};
this.get = function(key) {
return table[loseloseHashCode(key)];
};
this.remove = function(key) {
table[loseloseHashCode(key)] = undefined;
};
}
散列表中的冲突
当添加多个键值时,有一些键会有相同的散列值
var hash = new HashTable();
hash.put('Gandalf', 'gandalf@email.com');
hash.put('John', 'johnsnow@email.com');
hash.put('Tyrion', 'tyrion@email.com');
hash.put('Aaron', 'aaron@email.com');
hash.put('Donnie', 'donnie@email.com');
hash.put('Ana', 'ana@email.com');
hash.put('Jonathan', 'jonathan@email.com');
hash.put('Jamie', 'jamie@email.com');
hash.put('Sue', 'sue@email.com');
hash.put('Mindy', 'mindy@email.com');
hash.put('Paul', 'paul@email.com');
hash.put('Nathan', 'nathan@email.com');
依次出现在控制台的结果是:
19-Gandalf
29-John
16-Tyrion
16-Aaron
13-Donnie
13-Ana
5-Jonathan
5-Jamie
5-Sue
32-Mindy
32-Paul
10-Nathan
先添加一个print()辅助方法,在控制台中输出HashTable中的值。
遍历数组中的所有元素,当某个位置上有值的时候,在控制台输出位置和对应的值
this.print = function() {
for (var i = 0; i < table.length; i++) {
if (table[i] !== undefined) {
console.log(i + ":" + table[i]);
}
}
};
使用print()方法
hash.print();
控制台结果:
5:sue@email.com
10:nathan@email.com
13:ana@email.com
16:aaron@email.com
19:gandalf@email.com
29:johnsnow@email.com
32:paul@email.com
相同的位置,后添加的值将前面的值覆盖掉了
处理散列表中的冲突
1.分离链接法
首先在HashTable类内部添加一个新的辅助类,表示将要加入LinkedList实例的元素,此类将key和value存储在一个Object实例中
var ValuePair = function(key, value) {
this.key = key;
this.value = value;
this.toString = function() {
return '[' + this.key + '-' + this.value + ']';
};
};
重写put()方法,首先验证加入的新元素的位置是否已经被占据。如果没有,则在此位置初始化一个LinkedList类的实例;如果有则使用append()方法,向LinkedList实例中添加一个ValuePair实例
this.put = function(key, value) {
var position = loseloseHashCode(key);
if (table[position] == undefined) {
table[position] = new LinkedList();
}
table[position].append(new ValuePair(key, value));
};
重写get()方法,
this.get = function(key) {
var position = loseloseHashCode(key);
if (table[position] !== undefined) {
var current = table[position].getHead();
//遍历链表来寻找键值
while (current.next) {
if (current.element.key === key) {
return current.element.value;
}
current = current.next;
}
//检查元素在链表中的第一个或最后一个节点的情况
if (current.element.key === key) {
return current.element.value;
}
}
return undefined;
};
重写remove()方法,
this.remove = function(key) {
var position = loseloseHashCode(key);
if (table[position] !== undefined) {
var current = table[position].getHead();
while (current.next) {
if (current.element.key === key) {
table[position].remove(current.element);
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 false;
};
未完待续~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.线性探查