JavaScript数据结构与算法:集合与集合的扩展

这篇博客详细介绍了JavaScript中的Set数据结构,包括其特点、注意事项和常用操作,如add、delete、clear等。此外,还展示了如何扩展Set类以实现交集、并集、差集、补集和子集等高级功能。通过示例代码,展示了如何使用这些扩展方法,并提供了若干测试用例来验证其正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

集合 Set

1. Set 特点

集合内部元素唯一, 不允许重复, 支持增删改查的操作。

由于 JavaScript 实现了 ES6 中的 Set 类, 而且 Set 类也比较完善了。所以只需要扩展一下高级功能(并集、差集、交集、补集、子集)就可以愉快地使用了。

2. 注意事项

  1. 集合的每个元素并不仅仅是一个值, 而是一个键值对, 当运行以下代码时 const s = new Set([1,2,3]), 并不是单单向集合内插入 1,2,3 这 3 个值, 而是以 [1,1], [2,2], [3,3] 这种键值对形式保存数据;

  2. Set 内部判断内部元素是否相同用的是 ES6 新增的 Object.is (https://es6.ruanyifeng.com/#docs/object-methods)方法。Object.is=== 基本一致, 不同点是 Object.is 判断时 NaN 与 NaN 是相等的, 并且 +0-0 不相等; 而 === 判断时, NaNNaN 不相等, +0-0 相等;

  3. Set 原型对象上已经存在 add delete clear has keys values entries forEach 方法和 size 属性, 并可以使用 for ... of 去遍历, 以下是简单的示例:

const f = ()=> {console.log(1); return 2}
const s = new Set([`abc`, 123, true, new Date(), /\s/, f])
s.add(f)

console.log(s.has(f)) 

console.log(s)

s.delete(`abc`) 

console.log(s) 

// 使用 for ... of 遍历 set
for(let x of s) {
  console.log(x)
}
// 使用 for ... of 遍历 set.keys()
for(let k of s.keys()) {
  console.log(k)
}
// 使用 for ... of 遍历 set.values()
for(let v of s.values()) {
  console.log(v)
}
// 使用 for ... of 遍历 set.entries()
for(let e of s.entries()) {
  console.log(e)
}

console.log(s.size)

s.clear()

console.log(s.size)

3. 实现扩展后的 Set

class AdvanceSet extends Set {

  /**
   * @description 交集 , 返回一个新集合
   * @param  {...AdvanceSet} sets 
   * @returns {AdvanceSet | null}
   */
  getIntersection(...sets) {
    const union = this.getUnion(...sets)
    const intersection = new AdvanceSet()
    for(let s of union) {
      if(sets.every(set=> set.has(s))) {
        intersection.add(s)
      }
    }
    return intersection.size > 0 ? intersection : null
  }

  /**
   * @description 并集 , 返回一个新的集合
   * @param  {...AdvanceSet} sets 
   * @returns {AdvanceSet}
   */
  getUnion(...sets) {
    return sets.reduce((prev, cur)=> new AdvanceSet([...prev, ...cur]),this)
  }

  // 绝对补集 , 返回一个新的集合
  /**
   * @description 若给定全集U,有A⊆U,则A在U中的相对补集称为A的绝对补集(或简称补集),写作∁UA。 
   * 注意:学习补集的概念,首先要理解全集的相对性,补集符号∁UA有三层含义:
   * 1、A是U的一个子集,即A⊆U;
   * 2、∁UA表示一个集合,且∁UA⊆U;
   * 3、∁UA是由U中所有不属于A的元素组成的集合,∁UA与A没有公共元素,U中的元素分布在这两个集合中。
   * @param {AdvanceSet} universalSet 全集
   */
  getComplement(universalSet) {
    return new AdvanceSet([...universalSet].filter(element=> !this.has(element)))
  }

  /**
   * 是否是当前集合的补集
   * @param {AdvanceSet} universalSet 全集
   * @param {AdvanceSet} set 集合
   * @returns {Boolean} 以 universalSet 为全集, this 与 set 是否互为补集
   */
  isComplement(universalSet, anotherSet) {
    const isUniversalIncludesAnotherSet = [...anotherSet].every(element=> universalSet.has(element))
    return isUniversalIncludesAnotherSet 
      ? [...this].every(element=> universalSet.has(element) && !anotherSet.has(element))
      : false
  }

  /**
   * 当前集合是否为子集
   * @param {AdvanceSet} set 
   * @returns {Boolean}
   */
  isSubset(set) {
    return [...this].every(s=> set.has(s))
  }

  /**
   * 差集, 又称为相对补集, 返回一个新的集合
   * @description 若 A 和 B 是集合,则 A 在 B 中的相对补集是这样一个集合:其元素属于B但不属于A,B - A = { x| x∈B且x∉A}
   * @param {AdvanceSet} set 
   * @returns {AdvanceSet} 
   */
  getDifferenceSet(set) {
    return new AdvanceSet([...this].filter(element=> !set.has(element)))
  }

}```

以下是几个简单的测试
```javascript
const a = new AdvanceSet([1, 2, 3, 4])
const b = new AdvanceSet([`a`, `b`, `c`, 4])
const c = new AdvanceSet([{name : 'sk'}, {name : `loa`}, 4])
const d = new AdvanceSet([2, 3, 5])
const e = new AdvanceSet([1, 2, 3, 4, 5, 6, 7])
const f = new AdvanceSet([1, 4, 6, 7])

console.log(a.getUnion(b,c))
console.log(a.getIntersection(b,c))
console.log(d.isSubset(a))
console.log(a.getDifferenceSet(d))
console.log(d.getComplement(e))
console.log(d.isComplement(e,f))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值