今天稍微停下前进的脚步,来看下队栈的左右互搏术。 前两天学习了队列和栈之后,今天就能够试着来用两个栈实现队列的功能或者用两个队列来实现栈的功能。api
栈是先进后出,队列是先进先出,但能够用两个栈来模拟一个队列的功能,来实现队列中主要的 enqueue,dequeue, head 方法。数组
咱们所学的每一种数据结构,本质上都是对数据如何存储和使用的研究,这就必然涉及到增删改查,那么考虑实现这些方法时,咱们优先考虑如何实现数据的增长,只有存在了数据,才可以后续的操做。 因此如何实现队列中的增长数据方法 enqueue 呢?bash
接下来考虑队列中的删除 dequeue 方法数据结构
那队列的 head 方法呢学习
注意到了吗,这里又用到了 分而治之 的思想,还记得以前在哪里用过吗? 对,就是在给栈添加获取最小值方法的时候用过,当时也是用了两个栈来实现。 这里的话 enqueue 始终都操做 stack1,dequeue 和 head 方法始终都操做 stack2。ui
{
class StackQueue {
constructor() {
this.stack1 = new Stack();
this.stack2 = new Stack();
}
// 初始化stack,伪造私有方法
_initStack() {
if (this.stack1.isEmpty() && this.stack2.isEmpty()) {
return null; // 若是两个栈都是空的,那么队列中就没有元素
}
if (this.stack2.isEmpty()) {
// 若是stack2是空的,那么此时stack1必定不为空
while (!this.stack1.isEmpty()) {
this.stack2.push(this.stack1.pop()); // 把stack1的元素移除到stack2中
}
}
}
// 向队尾添加一个元素
enqueue(item) {
this.stack1.push(item); // 把数据存入到stack1中
}
// 删除队首的一个元素
dequeue() {
this._initStack();
return this.stack2.pop();
}
// 返回队首的元素
head() {
this._initStack();
return this.stack2.top();
}
}
var stackQueue = new StackQueue();
stackQueue.enqueue(1);
stackQueue.enqueue(4);
stackQueue.enqueue(8);
console.log(stackQueue.head()); // 1
stackQueue.dequeue();
stackQueue.enqueue(9);
console.log(stackQueue.head()); // 4
stackQueue.dequeue();
console.log(stackQueue.head()); // 8
console.log(stackQueue.dequeue()); // 8
console.log(stackQueue.dequeue()); // 9
}
复制代码
是否是以为很简单呢,梳理清楚队列和栈的特性就OK啦。 接下来让咱们继续修炼,用队列实现栈吧!this
队列是先进先出,栈是先进后出,(不断重复这两个知识点) 但能够用两个队列来模拟一个栈的功能,来实现栈中主要的 push,pop, top 方法。spa
你可能会想到利用上边的套路来实现这个需求,可是最后的结果你会发现是不正确的。由于 把 stack1 的元素移除到 stack2 中,此时的两个栈中的数据就首尾交换了,而若是此处换成队列 this.queue2. enqueue(this.queue1. dequeue()), 你会发现因为队列的特性,此时的两个队列仍是同样的,首尾并无交换。code
so 咱们来换个思路队列
和上边同样,咱们先考虑如何实现栈的存储数据 push 方法:
top 方法就简单了:
接下来思考比较复杂的 pop 方法:
在具体的实现中,须要额外定义两个变量,dataQueue 和 emptyQueue:
{
class QueueStack {
constructor() {
this.queue1 = new Queue();
this.queue2 = new Queue();
this.dataQueue = null; // 存放数据的队列
this.emptyQueue = null; // 存放备份数据的队列
}
// 初始化队列数据,模拟私有方法 确认哪一个队列存放数据,哪一个队列作备份
_initQueue() {
if (this.queue1.isEmpty()) {
this.dataQueue = this.queue2;
this.emptyQueue = this.queue1;
} else {
// 都为空的话 默认是 队列1
this.dataQueue = this.queue1;
this.emptyQueue = this.queue2;
}
}
// 往栈里压入一个元素
push(item) {
this._initQueue();
this.dataQueue.enqueue(item);
}
// 返回栈顶的元素
top() {
this._initQueue();
return this.dataQueue.tail();
}
// 把栈顶的元素移除
pop() {
this._initQueue();
while (this.dataQueue.size() > 1) {
// 利用备份队列转移数据,
this.emptyQueue.enqueue(this.dataQueue.dequeue()); // 数据队列和备份队列交换了身份
}
return this.dataQueue.dequeue(); // 移除数据队列的头部元素
}
}
var queueStack = new QueueStack();
queueStack.push(1);
queueStack.push(2);
queueStack.push(4);
console.log(queueStack.top()); // 栈顶是 4
console.log(queueStack.pop()); // 移除 4
queueStack.push(5);
console.log(queueStack.top()); // 栈顶变成 5
queueStack.push(6);
console.log(queueStack.pop()); // 移除 6
console.log(queueStack.pop()); // 移除5
console.log(queueStack.top()); // 栈顶是 2
}
复制代码
若是你有其余好的方法,欢迎留言
咱们利用基础的数组 api 实现了队列和栈的功能,再来回顾下(敲黑板,划重点了)
固然还有其余的队列和栈,我这里只介绍到了基础的实现。这个硬骨头,还需慢慢啃。
若是有错误或者错别字,还请给我留言指出,谢谢。