集合(Set)
李艳生
湖北师范大学
物理与电子科学学院
2020年春季
回顾
- 数组:随机访问
- 栈:后进先出
- 队列:先进先出
- 链表:增删效率高
引入
请大家思考我们要存储一组值不重复的有序数据,可以用什么数据结构?
内容
集合(重点)
集合运算(重点)
原生集合
任务
集合
- 集合实例:自然数集合 N = {0, 1, 2, 3, ...}
- 集合是一组不同对象的集
- 集合特征:无序性、确定性、唯一性
- 集合是一个没有重复元素,也没有顺序概念的数组
- 集合运算:并、交、差、子
创建集合
- JavaScript 的对象不允许一个键指向两个不同的属性,也保证了集合里的元素都是唯一的。
- 使用对象而不是数组来表示集合
- 键和值都用元素来表示,方便查找
创建集合
class Set{
constructor(){
this.items = {};
}
add(element){} //添加
delete(element){} //删除
has(element) //查找
clear() //清空
size() // 长度
values() //转数组
}
查找元素
- 如果元素在集合中,返回true,否则返回false。
- 用来检验某个元素是否存在于集合中
has(element){
return element in this.items;
// return Object.prototype.hasOwnProperty.call(this.items, element);
}
添加元素
- 对于给定的element,可以检查它是否存在于集合中。
- 如果不存在,就把element 添加到集合中,返回true,表示添加了该元素
- 如果集合中已经有了这个元素,就返回false,表示没有添加它。
添加元素
add(element) {
if (!this.has(element)) {
this.items[element] = element;
return true;
}
return false;
}
删除元素
- 首先,验证给定的element 是否存在于集合中
- 如果存在,就从集合中移除element,返回true,表示元素被移除;否则返回false
删除元素
delete(element) {
if (this.has(element)) {
delete this.items[element];
return true;
}
return false;
}
获取长度
size() {
return Object.keys(this.items).length;
}
清空
clear() {
this.items = {};
}
转数组
values(){
return Object.values(this.items);
}
集合使用
const 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.delete(1);
console.log(set.values()); // 输出[2]
set.delete(2);
console.log(set.values()); // 输出[]
集合运算
- 并集:返回一个包含两个集合中所有元素的新集合。
- 交集:返回一个包含两个集合中共有元素的新集合。
- 差集:返回一个包含所有存在于第一个集合且不存在于第二个集
合的元素的新集合。
- 子集:验证一个给定集合是否是另一集合的子集。
## 并集
#### 并集表示
$ A \bigcup B $
#### 并集定义
$ A \bigcup B = \\{ x | x \in A \bigvee x \in B \\} $
![并集图示](img/6/1.png)
并集
union(otherSet) {
const unionSet = new Set();
this.values().forEach(value => unionSet.add(value));
otherSet.values().forEach(value => unionSet.add(value));
return unionSet;
}
## 交集
#### 交集表示
$ A \bigcap B $
#### 交集定义
$ A \bigcap B = \\{ x | x \in A \bigwedge x \in B \\} $
![并集图示](img/6/2.png)
交集
intersection(otherSet) {
const intersectionSet = new Set();
const values = this.values();
for (let i = 0; i < values.length; i++) {
if (otherSet.has(values[i])) {
intersectionSet.add(values[i]);
}
}
return intersectionSet;
}
## 差集
#### 差集表示
$ A - B $
#### 差集定义
$ A - B = \\{ x | x \in A \bigwedge x \notin B \\} $
![并集图示](img/6/3.png)
差集
difference(otherSet) {
const differenceSet = new Set();
this.values().forEach(value => {
if (!otherSet.has(value)) {
differenceSet.add(value);
}
});
return differenceSet;
}
## 子集
#### 子集表示
$ A \subseteq B $
#### 子集定义
$ A \subseteq B = \\{ x | \forall x \in A \Rightarrow x \in B \\} $
![并集图示](img/6/4.png)
子集
isSubsetOf(otherSet) {
if (this.size() > otherSet.size()) {
return false;
}
let isSubset = true;
this.values().every(value => {
if (!otherSet.has(value)) {
isSubset = false;
return false;
}
return true;
});
return isSubset;
}
原生集合
- ECMAScript 2015 新增了Set 类作为JavaScript API
- ES2015 原生的Set 并没有实现了并集、交集、差集、子集
原生集合
const set = new Set();
set.add(1);
console.log(set.values()); // 输出@Iterator
console.log(set.has(1)); // 输出true
console.log(set.size); // 输出1
set.delete(1);
set.clear();
原生集合运算
const setA = new Set();
setA.add(1);
setA.add(2);
setA.add(3);
const setB = new Set();
setB.add(2);
setB.add(3);
setB.add(4);
并集
const union = (setA, setB) => {
const unionAb = new Set();
setA.forEach(value => unionAb.add(value));
setB.forEach(value => unionAb.add(value));
return unionAb;
};
console.log(union(setA, setB)); // 输出[1, 2, 3, 4]
交集
const intersection = (setA, setB) => {
const intersectionSet = new Set();
setA.forEach(value => {
if (setB.has(value)) {
intersectionSet.add(value);
}
});
return intersectionSet;
};
console.log(intersection(setA, setB)); // 输出[2, 3]
差集
const difference = (setA, setB) => {
const differenceSet = new Set();
setA.forEach(value => {
if (!setB.has(value)) {
differenceSet.add(value);
}
});
return differenceSet;
};
console.log(difference(setA, setB)); //输出[1]
扩展运算符
console.log(new Set([...setA, ...setB])); //并集
console.log(new Set([...setA].filter(x => setB.has(x)))); //交集
console.log(new Set([...setA].filter(x => !setB.has(x)))); //差集
任务
随机产生100个1000以内的随机数加入集合A中,再随机产生50个1000以内的随机数加入集合B中,求解A和B的并、交、差。