要点
- 单向链表,同时记录 head 和 tail
- 从 tail 入队,从 head 出队,否则出队时tail不好定位
- length 实时记录,不可遍历链表获取
/**
* @description 链表实现队列
* @author lsr
*/
interface ILinkListNode {
value: number
next: ILinkListNode | null
}
export class Queue {
private head: ILinkListNode | null = null
private tail: ILinkListNode | null = null
private len = 0
/**
* 在 tail 入队(尾部)
* @param value
*/
add(value: number) {
const newNode: ILinkListNode = {
value,
next: null
}
// 处理 head
if (this.head === null) {
this.head = newNode
}
// 判断 tail 是否有值,有值则入队
const tailNode = this.tail
if (tailNode) {
tailNode.next = newNode
}
// 重新设置 tail
this.tail = newNode
// 记录 length
this.len++
}
/**
* 在 head 出队(头部)
* @returns value | null
*/
delete(): number | null {
// 判断 head 是否有值,没有则返回 null
const headNode = this.head
// (尾部的 next 为null)
if (headNode === null) return null
if (this.len <= 0) return null
// 取出 value
const value = headNode.value
// 重新设置 head
this.head = headNode.next
// 记录 length
this.len--
return value
}
get length(): number {
// 实时记录 length,不需要遍历获取
return this.len
}
}
// 功能测试
// const customQueue = new Queue()
// console.log('length', customQueue.length)
// customQueue.add(100)
// customQueue.add(200)
// customQueue.add(300)
// console.log('length', customQueue.length)
// console.log(customQueue.delete())
// console.log(customQueue.delete())
// console.log(customQueue.delete())
// console.log(customQueue.delete())
// console.log(customQueue.delete())
// console.log('length', customQueue.length)
// 性能测试
const q1 = new Queue()
console.time('queue with list')
for (let i = 0; i < 10 * 10000; i++) {
q1.add(i)
}
for (let i = 0; i < 10 * 10000; i++) {
q1.delete()
}
console.timeEnd('queue with list') // 6.5009765625 ms
const q2 = []
console.time('queue with array')
for (let i = 0; i < 10 * 10000; i++) {
q2.push(i)
}
for (let i = 0; i < 10 * 10000; i++) {
q2.shift()
}
console.timeEnd('queue with array') // 346.950927734375 ms
单元测试
/**
* @description 链表实现队列 test
* @author lsr
*/
import { Queue } from '@/01-algorithm/queue-with-linkList'
describe('链表实现队列', () => {
it('add add length', () => {
const queue = new Queue()
expect(queue.length).toBe(0)
queue.add(100)
queue.add(200)
queue.add(300)
queue.add(400)
queue.add(500)
queue.add(600)
expect(queue.length).toBe(6)
})
it('delete add length', () => {
const queue = new Queue()
expect(queue.delete()).toBeNull()
queue.add(100)
queue.add(200)
queue.add(300)
queue.add(400)
queue.add(500)
queue.add(600)
expect(queue.delete()).toBe(100)
expect(queue.delete()).toBe(200)
expect(queue.delete()).toBe(300)
expect(queue.delete()).toBe(400)
expect(queue.length).toBe(2)
expect(queue.delete()).toBe(500)
expect(queue.length).toBe(1)
expect(queue.delete()).toBe(600)
expect(queue.length).toBe(0)
expect(queue.delete()).toBeNull()
expect(queue.delete()).toBeNull()
expect(queue.delete()).toBeNull()
expect(queue.length).toBe(0)
})
it('add add length again', () => {
const queue = new Queue()
queue.add(100)
queue.add(200)
expect(queue.delete()).toBe(100)
expect(queue.delete()).toBe(200)
expect(queue.length).toBe(0)
expect(queue.delete()).toBeNull()
queue.add(300)
queue.add(400)
expect(queue.length).toBe(2)
expect(queue.delete()).toBe(300)
expect(queue.delete()).toBe(400)
expect(queue.length).toBe(0)
})
})
性能分析
- 空间复杂度:都是O(n)
- add 时间复杂度:链表O(1),数组O(1)
- delete 时间复杂度:链表O(1),数组O(n)
划重点
- 链表,链表 vs 数组
- 数据结构的选择,比算法优化更重要
- 要有时间复杂度的敏感性