设计前中后队列
思路:使用两个双端队列来进行前中后插入,如queue1和queue2,当有插入时,判断两个队列元素数量是否相等。 不相等时往少的那个队列进行插入。始终保持两个队列元素相等或元素少一即可。
解题代码
- 首先创建一个链表节点类
- 然后创建一个队列类
- 最后创建两个双端队列,进行操作即可。
- 可用JS数组代替双端队列。
class MyNode { // 创建一个链表节点
constructor(val,next = null,pre = null) {
this.val = val;
this.pre = pre;
this.next = next;
}
insertPre(node) { // 在当前节点前插入节点
node.pre = this.pre;
node.next = this;
if (this.pre) this.pre.next = node; // 如果当前节点存在,那么前一个节点,向后指向传入节点
this.pre = node; // 当前节点向前指向传入节点
}
insertNext(node) { // 在当前节点后插入节点
node.pre = this; // 传入节点的前一位指向当前节点
node.next = this.next; // 传入节点的下一位指向当前节点的下一位
if (this.next) this.next.pre = node; // 如果下个节点存在,那么下个节点的前节点指向传入节点
this.next = node; // 当前节点下个节点指向传入节点
}
deletePre() { // 删除当前节点前一个节点
if (!this.pre) return;
let p = this.pre; // 保存前一个节点
this.pre = p.pre; // 向前再指向一步
if (p.pre) p.pre.next = this; // 前前一个节点的下节点指向当前节点,此时即删除成功。
}
deleteNext() { //删除当前节点的下一个节点
if (!this.next) return;
let p = this.next; // 保存下一个节点
this.next = p.next; // 向后指向一步
if (p.next) p.next.pre = this; // 下下一个节点的前一个节点指向当前节点,此时即删除成功。
}
}
class MyQueue { // 使用链表创建一个双端队列
constructor() {
const head = new MyNode();
const tail = new MyNode();
this.head = head // 头指针
this.tail = tail // 尾指针
this.head.next = this.tail; // 头尾互相指向
this.head.pre = null; // 当前节点的前一个节点初始化为空
this.tail.next = null;
this.tail.pre = this.head; // 头尾互相指向
this.cnt = 0; // 记录元素数量
}
pushBack(val) { // 从尾部入队
this.tail.insertPre(new MyNode(val));
this.cnt += 1;
}
pushFront(val) { // 从头部入队
this.head.insertNext(new MyNode(val));
this.cnt += 1;
}
popBack() { // 从尾部出队
if (this.isEmpty()) return -1;
let ret = this.tail.pre.val; // 被删除元素
this.tail.deletePre();
this.cnt -= 1;
return ret;
}
popFront() { // 从头部出队
if (this.isEmpty()) return -1;
let ret = this.head.next.val; // 被删除元素
this.head.deleteNext();
this.cnt -= 1;
return ret;
}
front() { // 查看头部元素
return this.head.next.val;
}
back() { // 查看尾部元素
return this.tail.pre.val;
}
isEmpty() { // 判空
return this.head.next === this.tail; // 头尾指针指向同一个地址代表为空
}
size() {
return this.cnt;
}
}
// 思路:使用两个双端队列来进行前中后插入,如queue1和queue2,当有插入时,判断两个队列元素数量是否相等
// 不相等时往少的那个队列进行插入。始终保持两个队列元素相等或元素少一即可。
var FrontMiddleBackQueue = function() {
this.queue1 = new MyQueue(); // 创建两个队列
this.queue2 = new MyQueue();
};
/**
* @param {number} val
* @return {void}
*/
FrontMiddleBackQueue.prototype.pushFront = function(val) {
this.queue1.pushFront(val); // 从q1头部插入
this.update();
};
/**
* @param {number} val
* @return {void}
*/
FrontMiddleBackQueue.prototype.pushMiddle = function(val) {
if (this.queue1.size() > this.queue2.size()) {
this.queue2.pushFront(this.queue1.popBack()) // 移动元素位置
}
this.queue1.pushBack(val);
};
/**
* @param {number} val
* @return {void}
*/
FrontMiddleBackQueue.prototype.pushBack = function(val) {
this.queue2.pushBack(val); // 往q2尾部插入
this.update();
};
/**
* @return {number}
*/
FrontMiddleBackQueue.prototype.popFront = function() {
if (this.isEmpty()) return -1;
let ret = this.queue1.popFront(); //从q1头部删除
this.update();
return ret;
};
/**
* @return {number}
*/
FrontMiddleBackQueue.prototype.popMiddle = function() {
// 因为q1和q2的关系是,q1要不等于q2要不多一个,所以从中间出队永远是从q1尾部删除。
if (this.isEmpty()) return -1;
let ret = this.queue1.popBack();
this.update();
return ret;
};
/**
* @return {number}
*/
FrontMiddleBackQueue.prototype.popBack = function() {
if (this.isEmpty()) return -1;
let ret;
if (this.queue2.isEmpty()){
ret = this.queue1.popBack();
} else {
ret = this.queue2.popBack(); // 删除应该从q2末尾开始
}
this.update();
return ret;
};
FrontMiddleBackQueue.prototype.update = function() { // 更新队列元素数量,如果偶数个,两个队列平分,奇数个,那么q1多一个
if (this.queue1.size() < this.queue2.size()) {
this.queue1.pushBack(this.queue2.front()) // 把q2头部元素添加到q1尾部
this.queue2.popFront();
}
if(this.queue1.size() === this.queue2.size() + 2){
this.queue2.pushFront(this.queue1.back()); // 把q1尾部元素添加到q2头部
this.queue1.popBack();
}
};
FrontMiddleBackQueue.prototype.isEmpty = function() {
return this.queue1.size() === 0; // 因为q1一定会比q2多一个元素,所以q1不存在就代表队列为空
};
/**
* 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()
*/