9.有序表、并查集

78 阅读1分钟
0.并查集实现
class UnionFindSet {
  constructor(list) {
    this.elementMap = new Map() // 元素map
    this.fatherMap = new Map() // 父节点map
    this.sizeMap = new Map() // 所在集合长度map

    for (let key of list) {
      let ele = this.createElement(key)
      this.elementMap.set(key, ele)
      this.fatherMap.set(ele, ele)
      this.sizeMap.set(ele, 1)
    }
  }

  createElement(value) {
    return { value }
  }

  findHead(ele){ // 查询头节点
    let path = [] // 收集沿途的所有元素,以便最后统一更新其头节点(扁平化),多次调用后,时间复杂度由O(N)逼近O(1)
    while (ele!==this.fatherMap.get(ele)) {
      path.push(ele)
      ele = this.fatherMap.get(ele)
    }
    while (path.length) {
      this.fatherMap.set(path.pop(),ele)
    }
    return ele
  }

  isSameSet(a, b) { // 是否属于同一个集合
    if (this.elementMap.has(a) && this.elementMap.has(b)) {
      return this.findHead(this.elementMap.get(a), this.elementMap.get(b))
    }
    return false
  }

  union(a, b) { // 合并两个集合
    if (this.elementMap.has(a) && this.elementMap.has(b)) {
      let aF = this.findHead(this.elementMap.get(a))
      let bF = this.findHead(this.elementMap.get(b))
      if (aF !== bF) {
        let big = this.sizeMap.get(aF) > this.sizeMap.get(bF) ? aF : bF
        let small = big == aF ? bF : aF
        this.fatherMap.set(small, big)
        this.sizeMap.set(big, this.sizeMap.get(aF) + this.sizeMap.get(bF))
        this.sizeMap.delete(small)
      }
    }
  }
}