zoukankan      html  css  js  c++  java
  • 《学习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.线性探查

    创建更好的散列函数

  • 相关阅读:
    中间人攻击
    RSA算法详解
    Scala的自定义类型标记
    新版gitbook导出pdf
    request中跟路径有关的api的分析
    struts2初始化探索(一)
    struts2入门教学
    区块链学习笔记(五)
    区块链学习笔记(四)
    区块链学习笔记(三)
  • 原文地址:https://www.cnblogs.com/u14e/p/5342476.html
Copyright © 2011-2022 走看看