栈与队列
概念
在计算机科学中,队列(Queue)是一种常见的数据结构,其遵循先进先出(FIFO)的原则。栈(Stack)是一种线性数据结构,它遵循特定的原则:后进先出(LIFO)。
相同点
- 线性结构: 栈和队列都是线性数据结构,它们都以线性的方式存储元素。栈中的元素是垂直堆叠的,而队列中的元素是水平排列的。
- 数据存储方式: 栈和队列都使用特定的方式存储和访问数据。栈采用后进先出(LIFO)的原则,而队列采用先进先出(FIFO)的原则。
- 基本操作: 它们都有基本的操作,例如添加元素和移除元素。在栈中,添加元素被称为“压栈”(Push),移除元素被称为“出栈”(Pop)。而在队列中,添加元素被称为“入队”(Enqueue),移除元素被称为“出队”(Dequeue)。
不同点
-
操作方式:
- 栈:遵循后进先出(LIFO)原则。最后进入栈的元素首先被移除。
- 队列:遵循先进先出(FIFO)原则。最先进入队列的元素首先被移除。
-
主要操作:
- 栈:主要操作是压栈(Push)和出栈(Pop)。压栈用于向栈顶添加元素,而出栈则移除并返回栈顶元素。
- 队列:主要操作是入队(Enqueue)和出队(Dequeue)。入队用于在队列尾部添加元素,而出队则移除并返回队列头部元素。
-
用途和应用场景:
- 栈:常见用途包括函数调用、表达式求值、回溯算法、内存管理(如函数调用栈)等。
- 队列:常见用途包括任务调度、缓冲区管理、广度优先搜索算法(BFS)等。
-
数据访问方式:
- 栈:只能通过栈顶访问和处理数据。
- 队列:可以通过队首和队尾访问和处理数据。
用栈实现队列
今天我们将用LeetCode题库中的用栈实现队列来介绍如何使用栈(Stack)来模拟队列的行为,实现队列的基本功能。
队列数据存储结构
首先我们通过两个栈来模拟队列的行为:
const MyQueue = function () {
this.stack1 = []; // 第一个栈用于入队操作
this.stack2 = []; // 第二个栈用于出队操作
}
然后再通过下列操作实现队列行为:
- 入队操作(push):将元素推入第一个栈
stack1。 - 出队操作(pop):如果
stack2不为空,则直接从stack2弹出栈顶元素;如果stack2为空,则将stack1的元素逐个弹出并推入stack2,然后从stack2弹出栈顶元素。 - 获取队首元素(peek):同样需要考虑
stack2的状态,若stack2为空,则先将stack1的元素推入stack2,然后返回stack2的栈顶元素。 - 判断队列是否为空(empty):当
stack1和stack2都为空时,队列为空。
MyQueue.prototype = {
push: function (x) {
this.statck1.push(x);
},
// FIFO
pop: function () {// 从队列首部移除元素
// 如果statck2为空,将statck1的元素pop到statck2中
if (this.statck2.length <= 0) {
while (this.statck1.length !== 0) {
this.statck2.push(this.statck1.pop());// 将statck1的元素pop到statck2中
}
}
return this.statck2.pop();// 如果statck2不为空,直接pop
},
// 拿到front的值
peek: function () {
if (this.statck2.length <= 0) {
while (this.statck1.length !== 0) {
this.statck2.push(this.statck1.pop());// 将statck1的元素pop到statck2中
}
}
const stack2Len = this.statck2.length;
return stack2Len && this.statck2[stack2Len - 1];// 如果statck2不为空,直接pop
},
// 判断队列是否为空
empty: function () {
return !this.statck1.length && !this.statck2.length; //如果statck1和statck2都为空,队列为空
}
}
在23-24行中:
const stack2Len = this.statck2.length;:这一行代码用于获取statck2栈的长度,并将长度值存储在stack2Len变量中。return stack2Len && this.statck2[stack2Len - 1];:在此处使用了逻辑与运算符&&,在逻辑表达式中,如果stack2Len的值不为零(即statck2栈不为空),则返回this.statck2[stack2Len - 1],即statck2栈顶元素。如果stack2Len的值为零(即statck2栈为空),则返回值为false。- 这样的设计是为了避免对空栈进行
pop()操作,因为在空栈上调用pop()方法将会导致错误。在peek()方法中,首先检查stack2Len的值是否为真(即是否大于零),如果为真,则返回statck2栈顶元素,否则返回false。
结论
利用两个栈的特性,我们成功地实现了队列的基本操作,包括入队、出队、获取队首元素以及判断队列是否为空。因此这个LeetCode问题也就解决了。