基础数据结构(八):队列拓展(双端队列和优先级队列)

79 阅读2分钟

双端队列

双端队列在单向队列的基础上解除了一部分限制:允许在队列的两端添加和删除元素。如此一来它便具有了队列性质,这样方便我们解决一些问题。比如leetcode的239题(以后会在刷队列算法题的章节讲解)。
对于双端队列的封装只需要在原有队列封装的基础上加上unshift和pop方法即可,这里不再给出详细代码。PS:原有队列封装

优先级队列

优先级队列是一种比普通队列更加高效的数据结构,他每次出队的元素都是具有最高优先级的,可以理解为元素按照关键字进行排序。优先级队列可以使用数组、链表等数据结构来实现,但是堆是最常用的实现方式。

优先级队列封装

我们可以提供一个节点类用来当做堆的元素,为了方便值的比较,该类必须有一个valueOf方法。对于优先级队列类的封装,只需借助上节封装的堆结构,就可以简单快速的实现:

import { Heap } from './heap';

class PriorityNode<T> {
  value: T;
  priority: number; // 优先级
  constructor(value: T, priority: number) {
    this.value = value;
    this.priority = priority;
  }
  valueOf() {
    return this.priority;
  }
}

class PriorityQueue<T> {
  // 使用堆存储优先级节点
  private heap: Heap<PriorityNode<T>>;
  // 由传入的type决定是最大堆还是最小堆 默认是最小堆
  constructor(type: HeapType = 0) {
    this.heap = new Heap(type);
  }
  // 入队
  enqueue(value: T, priority: number) {
    this.heap.insert(new PriorityNode(value, priority));
  }
  // 出队
  dequeue() {
    return this.heap.extractTop()?.value;
  }
  // 获取队首元素
  getFront() {
    return this.heap.getTop()?.value;
  }
  // 非空判断
  isEmpty() {
    return this.heap.isEmpty();
  }
  // 获取队列中元素的个数
  size() {
    return this.heap.size();
  }
}
// 测试
const pq = new PriorityQueue<string>();
pq.enqueue('c', 3);
pq.enqueue('d', 4);
pq.enqueue('e', 5);
pq.enqueue('a', 1);
pq.enqueue('b', 2);
while (!pq.isEmpty()) {
  console.log(pq.dequeue());
}
// a
// b
// c
// d
// e

这里根据传入的type决定使用最大堆或者最小堆,如果你的优先级是大的值优先级高,那么可以传入1使用最大堆,反之使用默认的最小堆即可。