Skip to content

数据结构

优先队列

js
class PriorityQueue {
  size = 0;
  pq = [];

  constructor(compareFn) {
    this.compareFn = compareFn;
  }

  // 上浮
  swim(x) {
    // 小堆:当x小,上浮(a-b>0),反之
    while (x > 1 && this.compare(this.parent(x), x)) {
      this.swap(x, this.parent(x));
      x = this.parent(x);
    }
  }
  // 下沉
  sink(x) {
    while (this.left(x) <= this.size) {
      var cur = this.left(x);

      if (this.right(x) <= this.size && this.compare(cur, this.right(x))) {
        cur = this.right(x);
      }
      if (this.compare(cur, x)) break;
      this.swap(cur, x);
      x = cur;
    }
  }
  // 插入堆底
  add(e) {
    this.size++;
    this.pq[this.size] = e;
    this.swim(this.size);
  }
  // 移除堆顶
  poll() {
    var cur = this.pq[1];
    this.swap(1, this.size);
    this.pq.pop();
    this.size--;
    this.sink(1);
    return cur;
  }
  // 获取堆顶元素
  peek() {
    return this.pq[1];
  }
  swap(i, j) {
    var temp = this.pq[i];
    this.pq[i] = this.pq[j];
    this.pq[j] = temp;
  }
  compare(i, j) {
    if (this.compareFn) {
      return this.compareFn(this.pq[i], this.pq[j]) > 0;
    }
    return this.pq[i] - this.pq[j] > 0;
  }
  left(x) {
    return x * 2;
  }
  right(x) {
    return x * 2 + 1;
  }
  parent(x) {
    return Math.floor(x / 2);
  }
  isEmpty() {
    return !this.size;
  }
}
// 大堆
var pq = new PriorityQueue((a, b) => b - a);
[1, 2, 3, 4, 5, 6].forEach((e) => pq.add(e));
console.log(pq.pq);
js
class PriorityQueue {
  size = 0;
  pq = [];

  constructor(compareFn) {
    this.compareFn = compareFn;
  }

  // 上浮
  swim(x) {
    // 改动处:x>1
    while (x > 0 && this.compare(this.parent(x), x)) {
      this.swap(x, this.parent(x));
      x = this.parent(x);
    }
  }
  // 下沉
  sink(x) {
    while (this.left(x) <= this.size) {
      var cur = this.left(x);

      if (this.right(x) <= this.size && this.compare(cur, this.right(x))) {
        cur = this.right(x);
      }
      if (this.compare(cur, x)) break;
      this.swap(cur, x);
      x = cur;
    }
  }
  // 插入堆底
  add(e) {
    this.pq[this.size] = e;
    this.swim(this.size);
    // 改动处:后加
    this.size++;
  }
  // 移除堆顶
  poll() {
    // 改动处:this.pq[1]
    var cur = this.pq[0];
    this.swap(0, this.size);
    this.pq.pop();
    this.size--;
    this.sink(0);
    return cur;
  }
  peek() {
    // 改动处:this.pq[1]
    return this.pq[0];
  }
  swap(i, j) {
    var temp = this.pq[i];
    this.pq[i] = this.pq[j];
    this.pq[j] = temp;
  }
  compare(i, j) {
    if (this.compareFn) {
      return this.compareFn(this.pq[i], this.pq[j]) > 0;
    }
    return this.pq[i] - this.pq[j] > 0;
  }
  left(x) {
    // 改动处:x*2
    return x * 2 + 1;
  }
  right(x) {
    // 改动处:x*2+1
    return x * 2 + 2;
  }
  parent(x) {
    // 改动处:x/2
    return Math.floor(x - 1 / 2);
  }
  isEmpty() {
    return !this.pq.length;
  }
}

优点:自排序,时间复杂度 O(log n)
缺点:出队顺序按照元素大小,无法按先进先出顺序

单调队列

js
class MonotonicQueue {
  maxq = [];

  pop(n) {
    // 如果出队不是最大元素,可能被压扁,则不用出队
    if (this.maxq[0] === n) {
      this.maxq.shift();
    }
  }
  push(n) {
    // 压扁中间元素,找到合适位置
    while (this.maxq.length && this.maxq[this.maxq.length - 1] < n) {
      this.maxq.pop();
    }
    this.maxq.push(n);
  }
  max() {
    return this.maxq[0];
  }
}

优点:单调递增或递减,时间复杂度 O(1),可以按先进先出顺序
缺点:不能获取完整数据(由于删除中间元素)