《学习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.线性探查

创建更好的散列函数

原文地址:https://www.cnblogs.com/u14e/p/5342476.html