使用双向链表结构实现
为什么需要双向链表?因为中间pushMiddle,popMiddle等操作,我们都要把断开的链表重新链接起来。
如何实现
createNode
额外的一个辅助函数createNode,由这个函数我们可以生成链表中的节点,而这个节点(node)包含了,数据data、上一指针perv,下一指针next,这三个数据
主函数(FrontMiddleBackQueue)
主函数中我们使用createNode函数创建head(link),即一个data=null,perv=null,next=null的node,以及size,lastNode(last)等属性。
pushFront
- 创建一个新的节点 newNode = this.createNode(val);
- 把newNode.next指向this.link.next,this.link.next.perv也指向newNode
- this.link.next指向newNode,newNode.perv指向this.link
- 如果size===0(last === null)那么就需要设置last = newNode
- size++
pushBack
- 创建newNode
- 判断size是不是等于0,如果等于0那么就调用pushFront的逻辑
- newNode.perv = this.last;
- this.last.next = newNode;
- this.last = newNode;
- size++
pushMiddle
- size<=2那么其实每次都是pushFront ,因为题目中有说,如果有两个中位数那么就取前面一位,所以size=0的时候我们直接走pushFron的逻辑,size===1的时候,1/2=0.5 意味着也是放在第一位;当size===2时,2/2 = 1那么我们也放在第一位;(第一位即head后面一位)
- 创建一个newNode
- 获取到middleIndex = Math.floor(size / 2);我们取得是floor那么while循环的时候要循环到-1(重要)因为循环是从head开始的。需要多循环一次。
- this.head循环middleIndex 我们将获取到middleNode(一般的链表结构我们只能通过遍历获取node节点)
- 用middle变量暂存middleNode;下图我们用head+node1+node2+node3来演示,那么middle就是node2
- middle.perv.next = newNode; newNode.perv = middle.perv (将前面两头先绑定好)
- middle.perv= newNode; newNode.next = middle (将后面两头绑定好)
- size++
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处理,不然中间断开链接和绑定链接的操作容易产生空指针。
下次有空我把这里的逻辑补上。
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()
*/