从零学习数据结构(6)- 集合

298 阅读3分钟

「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

关于集合

集合通常是由一组无序的,不能重复的元素构成

可以把集合看作为特殊的数组

  • 特殊之处在于里面的元素没有顺序,不能重复

  • 没有顺序意味着不能通过下标值进行访问,不能重复意味着相同的对象在集合中只会存在一份

集合的常见方法

  • add(value):向集合添加一个新的项

  • remove(value):从集合移除一个值

  • has(value):如果值在集合中,返回true,否则返回 false

  • clear():移除集合中的所有项

  • size():返回集合中元素的数量

  • values():返回一个包含集合中所有值的数组

集合的实现

代码

class Set {
  items = {}

  add(value) {
    if(this.has(value)) {
      return false
    }
    this.items[value] = value
    return true
  }

  remove(value) {
    if(this.has(value)) {
      delete this.items[value]
      return true
    }
    return false
  }

  has(value) {
    return this.items.hasOwnProperty(value)
  }

  clear() {
    this.items = {}
  }

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

  values() {
    return Object.keys(this.items)
  }
}

测试代码

const set = new Set()
console.log(set.add('abc'));   //true
console.log(set.add('abc'));   //false
console.log(set.add('cba'));   //true
console.log(set.add('nba'));   //true
console.log(set.values())      //[ 'abc', 'cba', 'nba' ]
console.log(set.remove('abc'))  //true
console.log(set.values())      //[ 'cba', 'nba' ]
console.log(set.size())        //2
set.clear() 
console.log(set.values())      //[]

集合间的操作

并集

对于给定的两个集合,返回一个包含两个集合中所有元素的新集合

  • 代码解析:

    1、创建一个新的集合,代表两个集合的并集

    2、遍历集合 1 中所有的值,添加放入新的集合

    3、遍历集合 2 中所有的值,并且添加放入新的集合

    4、返回新集合

交集

对于给定的两个集合,返回一个包含两个集合中共有元素的新集合

  • 代码解析:

    1、创建一个新的集合

    2、遍历集合 1 中的所有元素,判断该元素是否在集合 2 中

    3、在集合2 中,将该元素加入到新集合中

    4、返回新集合

差集

对于给定的两个集合,返回一个包含所有存在于第一个集合且不存在于第二个集合的元素的新集合

  • 代码解析:

    1、创建一个新的集合

    2、遍历集合 1 中的所有元素,判断该元素是否在集合 2 中

    3、如果不存在于集合2 中,将该元素加入到新集合中

    4、返回新集合

子集

验证一个给定集合是否是另一集合的子集

  • 代码解析:

    1、判断集合1是否大于集合2

    2、不大于的情况:

         - 判断集合1中的元素是否全部都在集合2中

          - 存在,那么就是子集

          - 有一个不存在,那就不是子集

代码实现

class Set {
      //...  
      
     union(otherSet) {
       const newSet = new Set()
       const valuesOfA = this.values()
       // 将原集合内容放入新的集合中
       for (let i = 0; i < this.size(); i ++) {
         newSet.add(valuesOfA[i])
       }
       // 将第二个集合的内容放入新的集合中
       const valuesOfB = otherSet.values()
       for (let i = 0; i < otherSet.size(); i++) {
         newSet.add(valuesOfB[i])
       }
       return newSet
     }

     intersection(otherSet) {
       const newSet = new Set()
       const valuesA = this.values()
       for (let i = 0; i < valuesA.length; i ++) {
         const item = valuesA[i]
         if (otherSet.has(item)) {
           newSet.add(item)
         }
       }
       return newSet
     }

     difference(otherSet) {
       const newSet = new Set()
       const valuesA = this.values()
       for (let i = 0; i < valuesA.length; i ++) {
         const item = valuesA[i]
         if (!otherSet.has(item)) {
           newSet.add(item)
         }
       }
       return newSet
     }

     subset(otherSet) {
       const valuesA = this.values()

       for (let i = 0; i < valuesA.length ; i ++) {
         const item = valuesA[i]
         if (!otherSet.has(item)) {
           return false
         }
       }
       return true
     }
}

测试代码

const set = new Set()
set.add('abc');
set.add('cba');
set.add('nba');

const set2 = new Set()
set2.add('qwe')
set2.add('wer')
set2.add('eqw')
set2.add('abc')

console.log(set.union(set2).values())    //[ 'abc', 'cba', 'nba', 'qwe', 'wer', 'eqw' ]
console.log(set.intersection(set2).values()) //[ 'abc' ]
console.log(set.difference(set2).values())   //[ 'cba', 'nba' ]
console.log(set.subset(set2))                //false