【JavaScript】如何用链表实现一个队列Queue?

132 阅读1分钟
  • 用数组实现的队列的dequeue方法用到了数组的shift方法,时间复杂度为O(n),而用链表实现的dequeue方法时间复杂度只为O(1),因为我们有保存指向头部的指针,所以直接让head = head.next就能实现dequeue,总体来说用链表实现队列效率更高

首先列好基本需求

// 链表里每个元素用节点表示
class Node {
    value;
    next;
    
    constructor(value){
        this.value = value;
    }
}

// 三个私有变量:
//    1. 存指向头部的指针,为了dequeue
//    2. 存指向尾部的指针,为了enqueue
//    3. 存队列长度,为了实时更新长度
class Queue {
    #head;
    #tail;
    #size;
    
    constructor(){}
    
    //入队方法
    enqueue(value){}
    
    //出队方法
    dequeue(){}
    
    //清除队列方法
    clear(){}
    
    //获取队列大小,用getter
    get size(){}
    
    // 用Symbol.iterator和Generator函数来实现对队列的迭代
    * [Symbol.iterator](){}
}

Array, Map, Set, String都有内置的迭代器,然而有些情况,你可能需要对一个对象进行迭代。我们可以用Symbol.iterator来自定义实现一个迭代器,同时他还能被for...of...迭代。

实现具体方法

class Node {
    value;
    next;
    
    constructor(value){
        this.value = value;
    }
}

class Queue {
    #head;
    #tail;
    #size;
    
    constructor() {
        this.clear();
    }
    
    enqueue(value) {
        const node = new Node(value);
        
        if (this.#head) {
            this.#tail.next = node;
            this.#tail = node;
        } else {
            this.#head = node;
            this.#tail = node;
        }
        
        this.#size++;
    }
    
    dequeue() {
        if(!this.#head) return;
        
        const first = this.#head;
        this.#head = this.#head.next;
        this.#size--;
        
        return first.value;
    }
    
    clear() {
        this.#head = undefined;
        this.#tail = undefined;
        this.#size = 0;
    }
    
    get size(){
        return this.#size;
    }
    
    * [Symbol.iterator]() {
        let curr = this.#head;
        
        while (curr) {
            yield curr.value;
            curr = curr.next;
        }
    }
}

使用

const queue = new Queue();
queue.enqueue('a');
queue.enqueue('b');

console.log(queue.size); 
// output: 2
console.log(...queue) 
// output: a b
for(const item of queue){
    console.log(item)
}
// output: a
//         b
console.log(queue.dequeue());
// output: a