javascript数据结构(六)字典和散列表

 集合、字典和散列表可以存储不重复的值。在集合中,我们感兴趣的是每个值本身,并把它当作主要元素。在字典中,我们用[键,值]的形式来存储数据。在散列表中也是一样(也是以[键,值]对的形式来存储数据)。但是两种数据结构的实现方式略有不同,本文将详细介绍字典和散列表这两种数据结构

转载于https://www.cnblogs.com/xiaohuochai/p/8183020.html

字典

  集合表示一组互不相同的元素(不重复的元素)。在字典中,存储的是[键,值]对,其中键名是用来查询特定元素的。字典和集合很相似,集合以[值,值]的形式存储元素,字典则是以[键,值]的形式来存储元素。字典也称作映射

【创建字典】

  与Set类相似,ECMAScript 6同样包含了一个Map类的实现,即我们所说的字典

  下面将要实现的类就是以ECMAScript 6中Map类的实现为基础的。它和Set类很相似(但不同于存储[值,值]对的形式,我们将要存储的是[键,值]对)

  这是我们的Dictionary类的骨架:

function Dictionary() {
    var items = {};
}

  与Set类类似,我们将在一个Object的实例而不是数组中存储元素。 然后,我们需要声明一些映射/字典所能使用的方法

复制代码

set(key,value):向字典中添加新元素。
remove(key):通过使用键值来从字典中移除键值对应的数据值。
has(key):如果某个键值存在于这个字典中,则返回true,反之则返回false。
get(key):通过键值查找特定的数值并返回。
clear():将这个字典中的所有元素全部删除。
size():返回字典所包含元素的数量。与数组的length属性类似。
keys():将字典所包含的所有键名以数组形式返回。
values():将字典所包含的所有数值以数组形式返回。

复制代码

【has】

  首先来实现has(key)方法。之所以要先实现这个方法,是因为它会被set和remove等其他方法调用。这个方法的实现和之前在Set类中的实现是一样的。使用JavaScript中的in操作符来验证一个key是否是items对象的一个属性。可以通过如下代码来实现:

this.has = function(key) { 
  return key in items;
}

【set】

  该方法接受一个key和一个value作为参数。我们直接将value设为items对象的key属性的值。它可以用来给字典添加一个新的值,或者用来更新一个已有的值

this.set = function(key, value) {
  items[key] = value; //{1}
}

【remove】

  它和Set类中的remove方法很相似,唯一的不同点在于我们将先搜索key(而不是value),然后我们可以使用JavaScript的delete操作符来从items对象中移除key属性

复制代码

this.remove = function(key) { 
  if (this.has(key)) {
    delete items[key];
    return true;
  }
  return false;
}

复制代码

【get】

  get方法首先会验证我们想要检索的值是否存在(通过查找key值),如果存在,将返回该值, 反之将返回一个undefined值

this.get = function(key) {
  return this.has(key) ? items[key] : undefined;
};

【values】

  首先,我们遍历items对象的所有属性值(行{1})。为了确定值存在,我们使用has函数来验证key确实存在,然后将它的值加入values数组(行{2})。最后,我们就能返回所有找到的值。这个方法以数组的形式返回字典中所有values实例的值:

复制代码

this.values = function() { 
  var values = {};
  for (var k in items) { //{1} 
    if (this.has(k)) {
      values.push(items[k]); //{2}
    }
  }
  return values;
};

复制代码

【clear】

this.clear = function(){
        items = {};
    };

【size】

this.size = function(){
        return Object.keys(items).length;
    };

【keys】

  keys方法返回在Dictionary类中所有用于标识值的键名。要取出一个JavaScript对象中所有的键名,可以把这个对象作为参数传入Object类的keys方法,如下:

this.keys = function() {
 return Object.keys(items);
}; 

【items】

  下面来验证items属性的输出值。我们可以实现一个返回items变量的方法,叫作getItems:

this.getItems = function() {
 return items;
} 

【完整代码】

  Dictionary类的完整代码如下所示

复制代码

function Dictionary(){

    var items = {};

    this.set = function(key, value){
        items[key] = value; //{1}
    };

    this.delete = function(key){
        if (this.has(key)){
            delete items[key];
            return true;
        }
        return false;
    };

    this.has = function(key){
        return items.hasOwnProperty(key);
        //return value in items;
    };

    this.get = function(key) {
        return this.has(key) ? items[key] : undefined;
    };

    this.clear = function(){
        items = {};
    };

    this.size = function(){
        return Object.keys(items).length;
    };

    this.keys = function(){
        return Object.keys(items);
    };

    this.values = function(){
        var values = [];
        for (var k in items) {
            if (this.has(k)) {
                values.push(items[k]);
            }
        }
        return values;
    };

    this.each = function(fn) {
        for (var k in items) {
            if (this.has(k)) {
                fn(k, items[k]);
            }
        }
    };

    this.getItems = function(){
        return items;
    }
}

复制代码

散列表

  下面将详细介绍HashTable类,也叫HashMap类,是Dictionary类的一种散列表实现方式

  散列算法的作用是尽可能快地在数据结构中找到一个值。如果要在数据结构中获得一个值(使用get方法),需要遍历整个数据结构来找到它。如果使用散列函数,就知道值的具体位置,因此能够快速检索到该值。散列函数的作用是给定一个键值,然后返回值在表中的地址

  举个例子,我们继续使用在前面使用的电子邮件地址簿。我们将要使用最常见的散列函数——“lose lose”散列函数,方法是简单地将每个键值中的每个字母的ASCII值相加

hashtable1

function HashTable() {
	var table = [];
	var Valuepair  = function(key, value) {
		this.key = key;
		this.value = value;
		this.toString = function() {
			return '[' + this.key + '-' + this.value + ']';
		}
	};

	var loseloseHashCode = function(key) {
		var hash = 0;
		for (var i = 0; i < key.length; i++) {
			hash += key.charCodeAt(i);
		}
		return hash % 37; 
	};
	// 替代loselose的方法
	var djb2HashCode = function(key){
		var hash = 5381;
		for (var i = 0; i < key.length; i++) {
			hash = hash * 33 + key.charCodeAt(i);
		}
		return hash % 1013;
	}
	// 分离连接
	this.put = function(key, value) {
		var position = loseloseHashCode(key);
		if (table[position] == undefined) {
			table[position] = new LinkList(); 
		}
		table[position].append(new Valuepair(key,value));
	};
	this.get = function(key){
		var position = loseloseHashCode(key);
		if (table[position] !== undefined) {
			var currrent = table[position].getHead();
			while(currrent.next) {
				if (currrent.element.key === key) {
					return currrent.element.value;
				}
				currrent = currrent.next;
			}
			if (current.element.key === key) {
				return currrent.element.value;
			}
		}
		return undefined;
	};
	this.remove = function(key){
		var position = loseloseHashCode(key);
		if (table[position] !== undefined) {
			var currrent = table[position].getHead();
			while(currrent.next){
				if (currrent.element.key === key) {
					table[position].remove(currrent.element);
					if (table[position].isEmpty()) {
						table[position] = undefined;
					}
					return true;
				}
				currrent = currrent.next;
			}
			if (currrent.element.key === key) {
				table[position].remove(currrent.element);
				if (table[position].isEmpty()) {
					table[position] = undefined;
				}
				return true;
			}
		}
		return false; 
	};
}
// 线性探查
function HashTable() {
	var table = [];
	var Valuepair  = function(key, value) {
		this.key = key;
		this.value = value;
		this.toString = function() {
			return '[' + this.key + '-' + this.value + ']';
		}
	};
	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);
		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);
		}
	};
	this.get = function(key) {
		var position = loseloseHashCode(key);

		if (table[position] !== undefined) {
			if (table[position].key === key) {
				return table[position].value;
			} else {
				var index = ++position;
				while(table[index] === undefined || table[index].key !== key) {
					index++;
				}
				if (table[position].key === key) {
					return table[index].value;
				}
			}
		}
		return undefined;		 
	};
	this.remove = function(key) {
		var position = loseloseHashCode(key);

		if (table[position] !== undefined) {
			if (table[position].key === key) {
				 table[position] = undefined;
			} else {
				var index = ++position;
				while(table[index] === undefined || table[index].key !== key) {
					index++;
				}
				if (table[position].key === key) {
					 table[index] = undefined;
				}
			}
		}
		return undefined;		 
	};

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值