集合是由一组无序且唯一(即不能重复)的项组成的。
这个数据结构使用了与有限集合相同的数学概念,但应用在计算机科学的数据结构中。
1、创建集合
在这里我们要实现的集合是以ES6中的Set类的实现为基础的 也就是我们使用对象而不是数组来表示集合 JS的对象不允许一个键指向两个不同的属性 也保证了集合里的元素都是唯一的
let items = {};
function Set() {
}
2、集合的方法:
add添加。
remove delete移除。
has如果值在集合中,返回true,否则返回false。
clear移除集合中的所有项。
size返回集合所包含元素的数量。与数组的length属性类似。
values返回一个包含集合中所有值的数组。
①add
this.add = function (value) {
if (!this.has(value)) {
items[value] = value; //{1}
return true;
}
return false;
};
//或者
this.has = function(value){
return items.hasOwnProperty(value);
};
let items = {};
function Set() {
this.has = function (value) {
return value in items;
};
this.add = function (value) {
if (!this.has(value)) {
items[value] = value; //{1}
return true;
}
return false;
};
}
//调用
let set = new Set();
set.add(1);
set.add(2);
console.log(items); //{1: 1, 2: 2}
②remove
this.remove = function (value) {
if (this.has(value)) {/*验证给定的value是否存在于集合中。
如果存在,就从集合中移除value*/
delete items[value];
return true;
}
return false;
};
③clear 清除
this.clear = function(){
items = {}; // {3}
};
④size 返回长度
/*使用JavaScript内建的Object类的一个内建函数:JavaScript
的Object类有一个keys方法,它返回一个包含给定对象所有属性
的数组。在这种情况下,可以使用这个数组的length属性来返回
items对象的属性个数。以上代码只能在现代浏览器中运行*/
this.size = function(){
return Object.keys(items).length;
};
//其他方法
/*手动提取items对象的每一个属性,记录属性的个数并返回这个
数字。这个方法可以在任何浏览器上运行,和之前的代码是等价的*/
this.sizeLegacy = function () {
let count = 0;
for (let key in items) { //遍历items对象的所有属性
if (items.hasOwnProperty(key))//检查它们是否是对象自身的属性
++count;/*如果是,就递增count变量的值,最后在方
法结束时返回这个数字。*/
}
return count;
};
不能简单地使用for-in语句遍历items对象的属性,并递增count变量的值。还需要使用hasOwnProperty方法(以验证items对象具有该属性),因为对象的原型包含了额外的属性(属性既有继承自JavaScript的Object类的,也有属于对象自身,未用于数据结构的)。
⑤values 值
//现代浏览器
this.values = function () {
let values = [];
for (let i = 0, keys = Object.keys(items); i < keys.length; i++) {
values.push(items[keys[i]]);
}
return values;
};
//任意浏览器
this.valuesLegacy = function () {
let values = [];
for (let key in items) { //{7}
if (items.hasOwnProperty(key)) { //{8}
values.push(items[key]);
}
}
return values;
};
3、方法的调用
let items = {};
function Set() {
this.has = function (value) {
return value in items;
};
this.add = function (value) {
if (!this.has(value)) {
items[value] = value;
return true;
}
return false;
};
this.remove = function (value) {
if (this.has(value)) {
delete items[value];
return true;
}
return false;
};
this.clear = function () {
items = {};
};
this.size = function () {
return Object.keys(items).length;
};
this.values = function () {
let values = [];
for (let key in items) {
if (items.hasOwnProperty(key)) {
values.push(items[key]);
}
}
return values;
};
}
let 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(1);
console.log(set.values()); //[2]
set.remove(2);
console.log(set.values()); //[]
4、集合的操作
并集
交集
差集:对于给定的两个集合,返回一个包含所有存在于第一个集合且不存在于第二个集
合的元素的新集合。
子集:验证一个给定集合是否是另一集合的子集。
①并集
this.union = function(otherSet){
let unionSet = new Set();//创建一个新的集合,代表两个集合的并集
let values = this.values(); /*接下来,获取第一个集合(当前的
Set类实例)所有的值(values),遍历并全部添加到代表并集的集合中*/
for (let i=0; i<values.length; i++){
unionSet.add(values[i]);
}
values = otherSet.values(); //对第二个集合做同样的事
for (let i=0; i<values.length; i++){
unionSet.add(values[i]);
}
return unionSet;
};
//调用
let setA = new Set();
setA.add(1);
setA.add(2);
setA.add(3);
let setB = new Set();
setB.add(3);
setB.add(4);
setB.add(5);
setB.add(6);
let unionAB = setA.union(setB);
console.log(unionAB.values());//[1, 2, 3, 4, 5, 6]
②交集
this.intersection = function (otherSet) {
let intersectionSet = new Set(); /*创建
一个新的Set实例,这样就能用它返回共有的元素*/
let values = this.values();
for (let i = 0; i < values.length; i++) { /**/{2}
if (otherSet.has(values[i])) { /*遍历当前Set实例
所有的值(行{2}),验证它们是否也存在于otherSet实例之中*/
intersectionSet.add(values[i]); /*可以用这一章前
面实现的has方法来验证元素是否存在于Set实例中。然后,如果这个值也
存在于另一个Set实例中,就将其添加到创建的intersectionSet变量中*/
}
}
return intersectionSet;
}
//调用
let setA = new Set();
setA.add(1);
setA.add(2);
setA.add(3);
let setB = new Set();
setB.add(2);
setB.add(3);
setB.add(4);
let intersectionAB = setA.intersection(setB);
console.log(intersectionAB.values());//[2, 3]
③差集
this.difference = function (otherSet) {
let differenceSet = new Set(); //{1}
let values = this.values();
for (let i = 0; i < values.length; i++) { //{2}
if (!otherSet.has(values[i])) { //{3}
differenceSet.add(values[i]); //{4}
}
}
return differenceSet;
};
//调用
let setA = new Set();
setA.add(1);
setA.add(2);
setA.add(3);
let setB = new Set();
setB.add(2);
setB.add(3);
setB.add(4);
let differenceAB = setA.difference(setB);
console.log(differenceAB.values()); //[1]
④子集
this.subset = function (otherSet) {
if (this.size() > otherSet.size()) { /*首先需要验证的
是当前Set实例的大小。如果当前实例中的元素比otherSet实例更多,
它就不是一个子集。子集的元素个数需要小于或等于要比较的集合。*/
return false;
} else {
let values = this.values();
for (let i = 0; i < values.length; i++) { /*接下来
要遍历集合中的所有元素*/
if (!otherSet.has(values[i])) { /*验证这些元素也
存在于otherSet中*/
return false;/*如果有任何元素不存在于otherSet
中,就意味着它不是一个子集,返回false。如果所有元素都存
在于otherSet中,该操作就不会被执行,那么就返回true。*/
}
}
return true; //{5}
}
};
//调用
let setA = new Set();
setA.add(1);
setA.add(2);
let setB = new Set();
setB.add(1);
setB.add(2);
setB.add(3);
let setC = new Set();
setC.add(2);
setC.add(3);
setC.add(4);
console.log(setA.subset(setB)); //true A是不是B的子集
console.log(setA.subset(setC)); //false A是不是C的子集