1鸠合
1.1鸠合的完成
鸠合是由一组无序且唯一(即不能反复)的项构成的。这个数据结构运用了与有限鸠合雷同 的数学观点,但应用在计算机科学的数据结构中。
鸠合中经常运用要领列表:
add(value):向鸠合中增添一个新的项。
remove(value):从鸠合中移除一个值。
has(value):假如在鸠合中,返回true,不然返回false。
clear():消灭鸠合中的一切项。
size():返回鸠合所包含元素的数目。
values():返回一个包含鸠合中一切值得数组。
union(otherSet):并集操纵,返回一个包含两个鸠合中一切元素的新鸠合。
intersection(otherSet):交集操纵,返回一个包含两个鸠合中共有元素的新鸠合。
difference(otherSet):差集操纵,返回一个包含摆布存在于第一个鸠合而且不存在于第二个鸠合的元素的新鸠合。
subset(otherSet):子集操纵,考证一个给定鸠合是不是是另一个鸠合的子集,返回true和false。
function Set() {
this.items = {};
}
Set.prototype = {
constructor: Set,
has: function(value) {
return value in this.items;
},
add: function(value) {
if (!this.has(value)) {
this.items[value] = value;
return true;
}
return false;
},
remove: function(value) {
if (this.has(value)) {
delete this.items[value];
return true;
}
return false;
},
clear: function() {
this.items = {};
},
size: function() {
return Object.keys(this.items).length;
},
values: function() {
return Object.keys(this.items);
},
union: function(otherSet) {
var unionSet = new Set();
var values = this.values();
for (var i = 0; i < values.length; i++) {
unionSet.add(values[i]);
}
values = otherSet.values();
for (var i = 0; i < values.length; i++) {
unionSet.add(values[i]);
}
return unionSet;
},
intersection: function(otherSet) {
var intersectionSet = new Set();
var values = this.values();
for (var i = 0; i < values.length; i++) {
if (otherSet.has(values[i])) {
intersectionSet.add(values[i]);
}
}
return intersectionSet;
},
difference: function(otherSet) {
var differenceSet = new Set();
var values = this.values();
for (var i = 0; i < values.length; i++) {
if (!otherSet.has(values[i])) {
differenceSet.add(values[i]);
}
}
return differenceSet;
},
subset: function(otherSet) {
if (this.size() > otherSet.size()) {
return false;
} else {
var values = this.values();
for (var i = 0; i < values.length; i++) {
if (!otherSet.has(values[i])) {
return false;
}
}
}
return true;
},
};
1.2鸠合的运用
var set = new Set();
set.add(1);
console.log(set.values());//["1"]
console.log(set.has(1));//true
console.log(set.size());//1
set.add(2);
console.log(set.values());//["1","2"]
console.log(set.has(2));//true
console.log(set.size());//2
set.remove(2);
console.log(set.values());//["1"]
交集、并集、子集、差集的运用。
//并集测试
var setA = new Set();
setA.add(1);
setA.add(2);
setA.add(3);
var setB = new Set();
setB.add(3);
setB.add(4);
setB.add(5);
setB.add(6);
var setAB = setA.union(setB);
console.log(setAB.values()); // ["1", "2", "3", "4", "5", "6"]
//交集测试
setA = new Set();
setA.add(1);
setA.add(2);
setA.add(3);
setB = new Set();
setB.add(2);
setB.add(3);
setB.add(4);
var intersectionAB = setA.intersection(setB);
console.log(intersectionAB.values()); // ["2", "3"]
//差集侧变乱
setA = new Set();
setA.add(1);
setA.add(2);
setA.add(3);
setB = new Set();
setB.add(2);
setB.add(3);
setB.add(4);
var differenceAB = setA.difference(setB);
console.log(differenceAB.values()); //["1"]
//子集测试
setA = new Set();
setA.add(1);
setA.add(2);
var setB = new Set();
setB.add(1);
setB.add(2);
setB.add(3);
setC = new Set();
setC.add(2);
setC.add(3);
setC.add(4);
console.log(setA.subset(setB)); //true
console.log(setA.subset(setC)); //false
2字典和散列表
鸠合、字典和散列表可以存储不反复的值。在鸠合中,我们感兴趣的是每一个值自身,并把它 看成重要元素。在字典中,我们用[键,值]的情势来存储数据。在散列表中也是一样(也是以[键, 值]对的情势来存储数据)。
2.1字典
鸠合示意一组互不雷同的元素(不反复的元素)。在字典中,存储的是[键,值] 对,个中键名是用来查询特定元素的。字典和鸠合很类似,鸠合以[值,值]的情势存储元素,字 典则是以[键,值]的情势来存储元素。字典也称作映照。下面是字典须要完成的要领:
set(key,value): 向字典中增添新元素。
remove(key): 经由过程运用键值来从字典中语出键值对应的数据值。
has(key): 假如某个键值存在于这个字典中,不然返回true,反之则返回false。
get(key): 经由过程键值查询特定的数值而且返回。
clear(): 将这个字典中的一切元素悉数删除。
size(): 返回字典中包含元素的数目。
keys(): 将字典所包含的一切键名以数组的情势返回。
values(): 将字典所包含的一切数值以数组的情势返回。
getItems(): 返回字典。
2.1.1字典的完成
function Dictionary() {
this.items = {};
}
Dictionary.prototype = {
constructor: Dictionary,
has: function(key) {
return key in this.items;
},
set: function(key, value) {
this.items[key] = value;
},
remove: function(key) {
if (this.has(key)) {
delete this.items[key];
return true;
}
return false;
},
get: function(key) {
return this.has(key) ? this.items[key] : undefined;
},
values: function() {
var values = [];
for (var key in this.items) {
if (this.has(key)) {
values.push(key);
}
}
return values;
},
clear: function() {
this.items = {};
},
size: function() {
return Object.keys(this.items).length;
},
keys: function() {
return Object.keys(this.items);
},
getItems: function() {
return this.items;
}
};
2.1.2字典的基础运用
var dictionary = new Dictionary();
console.log(dictionary.size()); //0
dictionary.set('first', 'huang');
dictionary.set('second', 'cheng');
dictionary.set('third', 'du');
console.log(dictionary.has('first')); //true
console.log(dictionary.get('second')); //cheng
console.log(dictionary.values()); // ["first", "second", "third"]
dictionary.remove('second');
console.log(dictionary.keys()); //["first", "third"]
console.log(dictionary.getItems()); //{ first="huang", third="du"}
2.2散列表
HashTable类,也叫HashMap类,是Dictionary类的一种散列表完成体式格局。散列算法的作用是尽量快地在数据结构中找到一个值。在之前的章节中,你已晓得假如 要在数据结构中取得一个值(运用get要领),须要遍历全部数据结构来找到它。假如运用散列 函数,就晓得值的详细位置,因而可以疾速检索到该值。散列函数的作用是给定一个键值,然后 返回值在表中的地点。
2.2.1基础版的散列表完成
在散列表中我们经由过程散列函数来肯定键值对的关联。基础要领以下:
put(key,value): 向散列表增添一个新的选项(也多是更新散列表)。
remove(key): 依据键值从散列表中移除值。
get(key): 返回依据键值检索到的特定值。
关于HashTable类来讲,我们不须要像ArrayList类一样从table数组中将位置也移除。由 于元素散布于全部数组范围内,一些位置会没有任何元素占有,并默以为undefined值。我们也 不能将位置自身从数组中移除(这会转变其他元素的位置),不然,当下次须要取得或移除一个 元素的时刻,这个元素会不在我们用散列函数求出的位置上。
//lose-los散列函数
function loseloseHashCode(key) {
var hash = 0;
for (var i = 0; i < key.length; i++) {
hash += key.charCodeAt(i);
}
return hash % 37;
}
function HashTable() {
this.table = [];
}
HashTable.prototype = {
constructor: HashTable,
put: function(key, value) {
var position = loseloseHashCode(key);
console.log(position + '- ' + key);
this.table[position] = value;
},
get: function(key) {
return this.table[loseloseHashCode(key)];
},
remove: function(key) {
this.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');
console.log(hash.get('Gandalf')); //gandalf@email.com
console.log(hash.get('Loiane')); //undefined
hash.remove('Gandalf');
console.log(hash.get('Gandalf')); //undefined
有时刻,一些键会有雷同的散列值。差别的值在散列表中对应雷同位置的时刻,我们称其为争执。当这类状况发作的时刻就要去处置惩罚它。处置惩罚争执有几种要领:星散链接、线性探查和双散列法,我们会引见前两种要领。关于星散链接和线性探查来讲,只须要重写三个要领:put、get和remove。这三个要领在 每种手艺完成中都是差别的。
2.2.2星散链接版散列表
为了完成一个运用了星散链接的HashTable实例,我们须要一个新的辅佐类来示意将要到场LinkedList实例的元素。我们管它叫ValuePair类。LinkedList的完成详细看javascript的数据结构与算法(一).html)。
星散链接:星散链接法包含为散列表的每一个位置建立一个链表并将元素存储在里面。它是处置惩罚争执的最简朴的要领,然则它在HashTable实例以外还须要分外的存储空间。
function HashTable() {
this.table = [];
//lose-los散列函数
function loseloseHashCode(key) {
var hash = 0;
for (var i = 0; i < key.length; i++) {
hash += key.charCodeAt(i);
}
//console.log(key + " - " + (hash % 37));
return hash % 37;
}
function ValuePair(key, value) {
this.key = key;
this.value = value;
this.toString = function() {
return '[' + this.key + ' - ' + this.value + ']';
}
}
if ((typeof this.put !== 'function') && (typeof this.put !== 'string')) {
HashTable.prototype.put = function(key, value) {
var position = loseloseHashCode(key);
if (this.table[position] === undefined) {
this.table[position] = new LinkedList();
}
this.table[position].append(new ValuePair(key, value));
};
HashTable.prototype.get = function(key) {
var position = loseloseHashCode(key);
if (this.table[position] !== undefined) {
var current = this.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;
}
} else {
return undefined;
}
};
HashTable.prototype.remove = function(key) {
var position = loseloseHashCode(key);
if (this.table[position] !== undefined) {
var current = this.table[position].getHead();
while (current.next) {
if (current.element.key === key) {
this.table[position].remove(current.element);
if (this.table[position].isEmpty()) {
this.table[position] = undefined;
}
return true;
}
current = current.next;
}
//搜检是不是是第一个或许末了一个
if (current.element.key === key) {
this.table[position].remove(current.element);
if (this.table[position].isEmpty()) {
this.table[position] = undefined;
}
return true;
}
}
return false;
};
}
}
var hash = new HashTable();
hash.put('Gandalf', 'gandalf@email.com');
hash.put('John', 'johnsnow@email.com');
//下面两个hash值雷同
hash.put('Aaron', 'huang@gmail.com');
hash.put('Tyrion', 'tyrion@email.com');
console.log(hash.get('Gandalf')); //gandalf@email.com
console.log(hash.get('Loiane')); //undefined
hash.remove('Gandalf');
console.log(hash.get('Gandalf')); //undefined
2.2.3线性探查版散列表
另一种处置惩罚争执的要领是线性探查。当想向表中某个位置到场一个新元素的时刻,假如索引为index的位置已被占有了,就尝试index+1的位置。假如index+1的位置也被占有了,就尝试 index+2的位置,以此类推。
function HashTable() {
this.table = []; //lose-los散列函数
function loseloseHashCode(key) {
var hash = 0;
for (var i = 0; i < key.length; i++) {
hash += key.charCodeAt(i);
}
//console.log(key + " - " + (hash % 37));
return hash % 37;
}
function ValuePair(key, value) {
this.key = key;
this.value = value;
this.toString = function() {
return '[' + this.key + ' - ' + this.value + ']';
}
}
if ((typeof this.put !== 'function') && (typeof this.put !== 'string')) {
HashTable.prototype.put = function(key, value) {
var position = loseloseHashCode(key);
if (this.table[position] === undefined) {
this.table[position] = new ValuePair(key, value);
} else {
var index = position + 1;
while (this.table[index] !== undefined) {
index++;
}
this.table[index] = new ValuePair(key, value);
}
};
HashTable.prototype.get = function(key) {
var position = loseloseHashCode(key);
if (this.table[position] !== undefined) {
if (this.table[position].key === key) {
return this.table[position].value;
} else {
var index = position + 1;
//index不凌驾数组的长度
while (((this.table[index] === undefined) || (this.table[index].key !== key)) && (index < this.table.length)) {
index++;
}
if (this.table[index] && (this.table[index].key === key)) {
return this.table[index].value;
} else {
return undefined;
}
}
} else {
return undefined;
}
};
HashTable.prototype.remove = function(key) {
var position = loseloseHashCode(key);
if (this.table[position] !== undefined) {
if (this.table[position].key === key) {
this.table[position] = undefined;
return true;
} else {
var index = position + 1;
while ((this.table[index] === undefined) || (this.table[index].key !== key)) {
index++;
}
if (this.table[index].key === key) {
this.table[index] = undefined;
return true;
}
}
} else {
return false;
}
};
}
}
var hash = new HashTable();
hash.put('Gandalf', 'gandalf@email.com');
hash.put('John', 'johnsnow@email.com');
//下面两个hash值雷同
hash.put('Aaron', 'huang@gmail.com');
hash.put('Tyrion', 'tyrion@email.com');
console.log(hash.get('Gandalf')); //gandalf@email.com
console.log(hash.get('Loiane')); //undefined
console.log(hash.remove('Gandalf')); //true
console.log(hash.get('Gandalf')); //undefined