用链表实现的队列类

53 阅读2分钟

很多人喜欢用数组的shift与push来实现出队与入队,但数组的unshift时间复杂度是O(n)的,我们可以用链表来实现一个入队时间复杂对为O(1)的简单队列类,实现代码如下:


enum ADDOREINSERT {  
  ADD = "ADD",  
  INSERT = "INSERT"  
}  
  
class NodePoint {  
  valany;  
  nextany;  
  constructor(val:any, next?:NodePoint) {  
    this.val = val || undefined;  
    this.next = next || null;  
  }  
}  
  
// 通用队列  
export const Queue = class {  
  headNodePoint | null;  
  tailNodePoint | null;  
  sizenumber;  
  constructor(val:any) {  
    // 初始化队列  
    if(val) {  
      this.head = this.tail = new NodePoint(val);  
      this.size = 1;  
    }else {  
      this.head = this.tail = null;  
      this.size = 0;  
    }  
  }  
    
  // 向队列里添加一个值,可以添加到头部,也可以添加到尾部,看具体调用的是pushQueue还是insertQueue  
  addVal(val:any, AddOrInsert:ADDOREINSERT) {  
    const node = new NodePoint(val);  
    if(this.size === 0) {  
      this.head = this.tail = node;  
    }else if(AddOrInsert === ADDOREINSERT.ADD) {  
      (this.tail as NodePoint).next = node;  
      this.tail = (this.tail as NodePoint).next;  
    }else if(AddOrInsert === ADDOREINSERT.INSERT) {  
      node.next = this.head;  
      this.head = node;  
    }  
    this.size++;  
  }  
    
  // 入队  
  pushQueue(...elements: any[]) {  
    // 遍历传入的值,向队列尾部添加值  
    for(let val of elements) {  
      this.addVal(val, ADDOREINSERT.ADD);  
    }  
  }  
  
  // 向队头插队  
  insertQueue(...elements: any[]) {  
    // 遍历传入的值,向队列头部添加值  
    /* 按照一般思维,如果要将[1,2,3] 插入 [4,5,6]头部,应该是[1,2,3,4,5,6],但若正序遍历1,2,3,插入到4,5,6  
       最终的结果会是[3,2,1,4,5,6],所以此处我们需要倒序插入到队列头  
    */  
    const len = elements.length;  
    for(let i=len-1; i>=0; i--) {  
      this.addVal(elements[i], ADDOREINSERT.INSERT);  
    }  
  }  
  
  // 出队,移除队头元素,返回队头元素的值  
  popQueue() {  
    const ret = this.head?.val || null;  
    if(this.size === 0) {  
      return null;  
    }  
    if(this.size === 1) {  
      this.head = this.tail = null;  
    }else {  
      this.head = (this.head as NodePoint).next;  
    }  
    this.size--;  
    return ret;  
  }  
  
  // 移除指定元素,返回false移除失败,返回true移除成功  
  // 根据值进行匹配,对引用类型的值总是能正确执行,对基本数据类型就只移除第一个匹配到的元素  
  removeVal(val: any) {  
    // 队列里没有值  
    if(this.size === 0) {  
      return false;  
    }  
    // 若只有一个值,则头节点与尾节点指向同一个值,将头尾节点都置为null即可  
    if(this.size === 1) {  
      this.head = this.tail = null;  
    }else { // 否则找到对应的元素,将该元素指针置为null,并指向下一个元素  
      let cur = this.head;  
      // 声明一个慢指针pre,记录找到的节点的前一个节点  
      let pre = null;  
      // 遍历队列,找到与val相等的节点  
      while(cur && cur.val !== val) {  
        pre = cur;  
        cur = cur.next;  
      }  
      // 如果找到的节点是null,那么返回false  
      if(!cur) {  
        return false;  
      }  
      // 如果找到的节点是首节点,将首节点指向下一个节点就好  
      if(cur === this.head && cur.val === val) {  
        this.head = this.head.next;  
      }else if(cur === this.tail && cur.val === val) { // 如果找到的是尾节点,则将尾节点指向前一个节点,再将next指向null  
        this.tail = pre;  
        (this.tail as NodePoint).next = null;  
      }else if(cur.val === val) { // 找到的是中间的节点,则将上一个节点的next指向此节点的next即可  
        (pre as NodePoint).next = cur.next;  
      }  
      this.size--;  
      return true;  
    }  
  }  
    
}