TypeScript 任务队列简介
任务队列(Queue)是编程中最基础的数据结构之一,它遵循 FIFO(先进先出)原则。想象一下商店里的普通队列:第一个排队的顾客最先被服务。在编程中,任务队列被广泛使用:从服务器处理请求到浏览器中管理异步操作。
在本文中,我们将探讨如何在 TypeScript 中创建和使用任务队列。您将学习如何对队列进行类型化、实现基本方法以及在实际项目中应用它。本材料面向熟悉 TypeScript 基础的初学者。
队列的基本操作
任何任务队列都应支持以下几个基本操作:
- enqueue(在队列末尾添加元素);
- dequeue(从队列开头取出元素);
- peek(查看第一个元素而不删除);
- isEmpty(检查队列是否为空);
- size(获取元素数量)。
在 TypeScript 中,我们可以基于数组或链表实现队列。为简单起见,我们从数组开始。
基于数组的队列实现
让我们创建一个使用泛型的 Queue 类——这允许存储任何类型的数据:
class Queue<T> { private items: T[] = [];
// 在队列末尾添加元素 enqueue(element: T): void { this.items.push(element); }
// 删除并返回第一个元素 dequeue(): T | undefined { return this.items.shift(); }
// 查看第一个元素而不删除 peek(): T | undefined { return this.items[0]; }
// 检查队列是否为空 isEmpty(): boolean { return this.items.length === 0; }
// 获取队列大小 size(): number { return this.items.length; }}现在可以为任何数据类型创建队列:
// 字符串队列const stringQueue = new Queue<string>();stringQueue.enqueue('任务 1');stringQueue.enqueue('任务 2');console.log(stringQueue.dequeue()); // '任务 1'
// 数字队列const numberQueue = new Queue<number>();numberQueue.enqueue(10);numberQueue.enqueue(20);console.log(numberQueue.peek()); // 10基于数组实现的缺点
JavaScript/TypeScript 中的 shift() 方法复杂度为 O(n),因为删除第一个元素后所有其他元素都会移动。对于大量数据来说,这效率不高。解决方案是基于对象或链表实现队列。
使用对象优化的队列
为了避免元素移动,我们将元素存储在对象中并跟踪开始和结束的索引:
class OptimizedQueue<T> { private items: Record<number, T> = {}; private head: number = 0; private tail: number = 0;
enqueue(element: T): void { this.items[this.tail] = element; this.tail++; }
dequeue(): T | undefined { if (this.isEmpty()) { return undefined; } const item = this.items[this.head]; delete this.items[this.head]; this.head++; return item; }
peek(): T | undefined { return this.items[this.head]; }
isEmpty(): boolean { return this.tail === this.head; }
size(): number { return this.tail - this.head; }}现在 enqueue 和 dequeue 操作的时间复杂度为 O(1)——常数时间,与数据量无关。