定义

先进者先出。就按照平时排队的的形式理解,先到先得。

操作特性

数据结构:栈一样,也是“操作受限”的线性表,只允许在一端插入和删除数据。相比于数据结构:数组数据结构:链表,更少的操作结构,意味着更加可控,不易出错的状态。

顺序队列:用数组实现的队列

优点:队列大小有限,超出队列的请求会被拒绝,适合时间敏感系统 缺点:不容易设计合适队列大小,太大导致等待的请求太多,小了会导致无法利用系统资源、发挥最大性能。

class ArrayQueue {
  private items: string[]; // 数组
  private n: number; // 数组大小
  private head = 0; // 队头指针
  private tail = 0; // 队尾指针
 
  // 初始化数组,申请一个大小为 n 的数组空间
  constructor(n: number) {
    this.items = [];
    this.n = n;
  }
 
  // 入队操作
  enqueue(element: string): boolean {
    // 如果 tail 指针和 n 相等,表示队列已满,无法再加入元素
    if (this.tail === this.n) {
	    // tail === n & head === 0,表示整个队列都占满了
	    if (head === 0) return false
	    // 在这里进行一次性集体数据搬移,避免每次出队都搬移一次数据,将出队时间复杂度从 O(n) 降低至 O(1)
		for (let i = head; i< tail; i++) {
			items[i - head] = items[i]
		}
		// 搬移完之后重新更新 head 和 tail
		tail -= head
		head = 0
    }
    this.items[this.tail] = element;
    this.tail++;
    return true;
  }
 
  // 出队操作
  dequeue(): string | null {
    // 如果 head 指针和 tail 相等,表示队列为空,无法再弹出元素
    if (this.head === this.tail) return null;
    const element = this.items[this.head];
    this.head++;
    return element;
  }
}

链式队列:基于链表的队列实现方法

优点:可以实现无限支持排队的无界队列 缺点:可能导致排队时间过长,不适合响应时间敏感的系统

class LinkedNode {
  constructor(element) {
    this.element = element;
    this.next = null;
  }
}
 
class QueueBasedOnLinkedList {
  constructor() {
    this.head = null;
    this.tail = null;
  }
 
  enqueue(value) {
    if (this.head === null) {
      this.head = new LinkedNode(value);
      this.tail = this.head;
    } else {
      this.tail.next = new LinkedNode(value);
      this.tail = this.tail.next;
    }
  }
 
  dequeue() {
    if (this.head !== null) {
      const value = this.head.element;
      this.head = this.head.next;
      return value;
    } else {
      return -1;
    }
  }
}

循环队列:避免顺序队列中的数据搬移

// 这里的难点在于队空和队满的判断
class CircularQueue {
  private items: string[];
  private n: number;
  private head = 0;
  private tail = 0;
 
  constructor(n: number) {
    this.items = new Array(n);
    this.n = n;
  }
 
  enqueue(item: string): boolean {
    // 队列满了
    if ((this.tail + 1) % this.n == this.head) return false;
    this.items[this.tail] = item;
    this.tail = (this.tail + 1) % this.n;
    return true;
  }
 
  dequeue(): string | null {
    if (this.head === this.tail) return null;
    const ret = this.items[this.head];
    this.head = (this.head + 1) % this.n;
    return ret;
  }
}

生产中用的队列

大部分资源有限的场景,当没有空闲资源时,基本都可以通过”队列”数据结构来实现排队。

阻塞队列

  • 在队列为空时,从队头取数据会被阻塞,只有队列有了数据才能返回。
  • 在队列满时,从队尾取数据会被阻塞,只有队列有空闲位置才能插入数据。
  • “生产者(head)-消费者(tail)模型”下,通过配置“生产者”和“消费者”的个数,来提高数据的处理效率。(分布式构建?)

并发队列

基于数组的循环队列,利用 CAS 原子操作,实现高效的并发队列。比如 Disruptor