前言

几乎每种编程语言中,都有集合结构。集合比较常见的实现方式是哈希表,这里使用 JavaScript 的 Object 进行封装,这里我们来介绍如何自己封装一个集合Set类

集合特点

  • 集合通常是由一组无序的不能重复的元素构成。
  • 数学中常指的集合中的元素是可以重复的,但是计算机中集合的元素不能重复。
  • 集合是特殊的数组
    • 特殊之处在于里面的元素没有顺序,也不能重复。
    • 没有顺序意味着不能通过下标值进行访问,不能重复意味着相同的对象在集合中只会存在一份。

集合的封装

集合常见的操作

  • add(value) 向集合添加一个新的项。
  • remove(value) 从集合移除一个值。
  • has(value) 如果值在集合中,返回 true,否则返回 false。
  • clear() 移除集合中的所有项。
  • size() 返回集合所包含元素的数量。与数组的 length 属性类似。
  • values() 返回一个包含集合中所有值的数组。
  • 还有其他的方法,用的不多,这里不做封装。

代码完整实现

  1. class Set{
  2. constructor(){
  3. this.items={}
  4. }
  5. add(value){
  6. if(this.has(value)){
  7. return false
  8. }
  9. this.items[value]=value;
  10. return true
  11. }
  12. has(value){
  13. return this.items.hasOwnProperty(value);
  14. }
  15. remove(value){
  16. if(this.has(value)){
  17. return false
  18. }
  19. delete this.items[value]
  20. return true
  21. }
  22. clear(){
  23. this.items={}
  24. }
  25. size(){
  26. return Object.keys(this.items).length
  27. }
  28. values(){
  29. return Object.values(this.items)
  30. }
  31. }

some tests

const set = new Set();

// add() 测试
set.add("abc");
set.add("abc");
set.add("123");
set.add("zxc");
console.log(set); //--> {items: {123: "123", abc: "abc", zxc: "zxc"}}

// has() 测试
console.log(set.has("123")); //--> true
console.log(set.has("456")); //--> false

// remove() 测试
set.remove("abc");
console.log(set); //--> {items: {123: "123", zxc: "zxc"}}

// size() 测试
console.log(set.size()); //--> 2

// values() 测试
console.log(set.values()); //--> ["123", "zxc"]

// clear() 测试
set.clear();
console.log(set.values()); //--> []

集合的常见应用(集合间操作)

  • 并集:对于给定的两个集合,返回一个包含两个集合中所有元素的新集合。
  • 交集:对于给定的两个集合,返回一个包含两个集合中共有元素的新集合。
  • 差集:对于给定的两个集合,返回一个包含所有存在于第一个集合且不存在于第二个集合的元素的新集合。
  • 子集:验证一个给定集合是否是另一个集合的子集。

数据结构(五)———集合(Set) - 图1

代码实现

 union(otherSet) {
    // 1、创建一个新集合
    let unionSet = new Set();
    // 2、将当前集合(this)的所有 value,添加到新集合(unionSet)中
    for (let value of this.values()) {
        unionSet.add(value);
    }
    // 3、将 otherSet 集合的所有 value,添加到新集合(unionSet)中
    for (let value of otherSet.values()) {
        unionSet.add(value); // add() 已经有重复判断
    }

    return unionSet;
}
  intersection(otherSet){
    let intersection=new Set();
    for (const value of this.values()) {
      if(otherSet.has(value)){
        intersection.add(value)
      }
    }
    return intersection
  }
  difference(otherSet) {

    // 1、创建一个新集合
    let differenceSet = new Set();

    // 2、从当前集合中取出每一个 value,判断是否在 otherSet 集合中存在,不存在的即为差集
    for (let value of this.values()) {
        if (!otherSet.has(value)) {
            differenceSet.add(value);
        }
    }

    return differenceSet;
}
subset(otherSet) {

  // 从当前集合中取出每一个 value,判断是否在 otherSet 集合中存在,有不存在的返回 false
  // 遍历完所有的,返回 true
  for (let value of this.values()) {
      if (!otherSet.has(value)) {
          return false;
      }
  }
  return true;
}