Leetcode-1670-设计前中后队列

149 阅读2分钟

使用双向链表结构实现

为什么需要双向链表?因为中间pushMiddle,popMiddle等操作,我们都要把断开的链表重新链接起来。

如何实现

createNode

额外的一个辅助函数createNode,由这个函数我们可以生成链表中的节点,而这个节点(node)包含了,数据data、上一指针perv,下一指针next,这三个数据

主函数(FrontMiddleBackQueue)

主函数中我们使用createNode函数创建head(link),即一个data=null,perv=null,next=null的node,以及size,lastNode(last)等属性。

pushFront

  1. 创建一个新的节点 newNode = this.createNode(val);
  2. 把newNode.next指向this.link.next,this.link.next.perv也指向newNode
  3. this.link.next指向newNode,newNode.perv指向this.link
  4. 如果size===0(last === null)那么就需要设置last = newNode
  5. size++

image-20211206221856486

pushBack

  1. 创建newNode
  2. 判断size是不是等于0,如果等于0那么就调用pushFront的逻辑
  3. newNode.perv = this.last;
  4. this.last.next = newNode;
  5. this.last = newNode;
  6. size++

image-20211206222544286

pushMiddle

  1. size<=2那么其实每次都是pushFront ,因为题目中有说,如果有两个中位数那么就取前面一位,所以size=0的时候我们直接走pushFron的逻辑,size===1的时候,1/2=0.5 意味着也是放在第一位;当size===2时,2/2 = 1那么我们也放在第一位;(第一位即head后面一位)
  2. 创建一个newNode
  3. 获取到middleIndex = Math.floor(size / 2);我们取得是floor那么while循环的时候要循环到-1(重要)因为循环是从head开始的。需要多循环一次。
  4. this.head循环middleIndex 我们将获取到middleNode(一般的链表结构我们只能通过遍历获取node节点)
  5. 用middle变量暂存middleNode;下图我们用head+node1+node2+node3来演示,那么middle就是node2
  6. middle.perv.next = newNode; newNode.perv = middle.perv (将前面两头先绑定好)
  7. middle.perv= newNode; newNode.next = middle (将后面两头绑定好)
  8. size++

image-20211206224441567

FrontMiddleBackQueue.prototype.pushMiddle = function(val) {
    //仅判断this.size === 0 也是可以的主要是处理 this.last
    if(this.size === 0){
        this.pushFront(val)
    }else{
    let newNode = this.createNode(val);
        let midIndex = Math.floor(this.size/2) ;
        let middle = this.head
        while(midIndex!==-1){
            middle = middle.next
            midIndex--
        }
        newNode.next = middle
        newNode.perv = middle.perv
        middle.perv.next = newNode;
        middle.perv = newNode
        this.size++
    }  
};

pop逻辑

popFront没什么需要注意的

pushBack的时候需要注意重置this.last

pushMiddle的时候需要注意size,要是size < 2那么就当成popFront处理,不然中间断开链接和绑定链接的操作容易产生空指针。

下次有空我把这里的逻辑补上。

github文章同步链接

var FrontMiddleBackQueue = function() {
   this.head = this.createNode();
   this.last = null;
   this.size = 0;
};FrontMiddleBackQueue.prototype.createNode = function(data = null,perv = null,next=null){
    return {
        data,
        perv,
        next
    }
}
​
/** 
 * @param {number} val
 * @return {void}
 */
FrontMiddleBackQueue.prototype.pushFront = function(val) {
    let newNode = this.createNode(val);
    
    if(this.size === 0){
        this.head.next = newNode;
        this.last = newNode;
        newNode.perv = this.head;
    }else{
        const temp = this.head;
        temp.next.perv = newNode;
        newNode.next = temp.next;
        newNode.perv = temp;
        this.head.next = newNode
    }
    this.size++
};
​
/** 
 * @param {number} val
 * @return {void}
 */
FrontMiddleBackQueue.prototype.pushMiddle = function(val) {
    if(this.size === 0){
        this.pushFront(val)
    }else{
    let newNode = this.createNode(val);
        let midIndex = Math.floor(this.size/2) ;
        let middle = this.head
        while(midIndex!==-1){
            middle = middle.next
            midIndex--
        }
        newNode.next = middle
        newNode.perv = middle.perv
        middle.perv.next = newNode;
        middle.perv = newNode
        this.size++
    }  
};
​
/** 
 * @param {number} val
 * @return {void}
 */
FrontMiddleBackQueue.prototype.pushBack = function(val) {
    let newNode = this.createNode(val)
    if(this.size === 0){
        this.pushFront(val)
    }else{
        newNode.perv = this.last;
        this.last.next = newNode;
        this.last = newNode
        this.size++
    }
};
​
/**
 * @return {number}
 */
FrontMiddleBackQueue.prototype.popFront = function() {
    if(this.size === 0){
        return -1;
    }
    if(this.size === 1){
        let rs = this.head.next.data;
        this.head.next = null;
        this.last = null
        this.size = 0
        return rs;
    }
    let rs = this.head.next.data;
    let temp =  this.head.next
    temp.next.perv = this.head;
    this.head.next = temp.next;
    this.size--
    return rs;
};
​
/**
 * @return {number}
 */
FrontMiddleBackQueue.prototype.popMiddle = function() {
    if(this.size < 2){
       return this.popFront();
    }
    let midIndex = Math.ceil(this.size/2);
    let middle = this.head
    while(midIndex!== 0){
        middle = middle.next;
        midIndex--
    }
    let rs =  middle.data;
    middle.perv.next = middle.next;
    middle.next.perv = middle.perv;
    this.size--
    return rs
};
​
/**
 * @return {number}
 */
FrontMiddleBackQueue.prototype.popBack = function() {
    if(this.size === 0){
        return -1;
    };
    if(this.size === 1){
       return this.popFront();
    }
    let rs = this.last.data;
    this.last.perv.next = null;
    this.last = this.last.perv;
    this.size--
    return rs
};
​
/**
 * Your FrontMiddleBackQueue object will be instantiated and called as such:
 * var obj = new FrontMiddleBackQueue()
 * obj.pushFront(val)
 * obj.pushMiddle(val)
 * obj.pushBack(val)
 * var param_4 = obj.popFront()
 * var param_5 = obj.popMiddle()
 * var param_6 = obj.popBack()
 */