本文的网课内容学习自B站左程云老师的算法详解课程,旨在对其中的知识进行整理和分享~
一.利用栈实现队列
题目:用栈实现队列
算法原理
一、数据结构定义
- 两个栈
- 这个算法使用了两个栈,分别是
in
栈和out
栈。 - 在
MyQueue
类中定义为public Stack<Integer> in;
和public Stack<Integer> out;
。这两个栈用于存储数据,模拟队列的操作。
- 这个算法使用了两个栈,分别是
二、构造函数
- 初始化
- 在
MyQueue
的构造函数public MyQueue()
中,分别初始化了in
栈和out
栈,创建了两个空的栈,为后续操作做准备。
- 在
三、inToOut
方法(数据转移操作)
- 转移条件
- 这个方法的目的是将
in
栈中的数据转移到out
栈中。 - 转移的条件有两个:
- 首先,
out
栈必须为空(if (out.empty())
),这样可以保证数据的顺序是按照队列先进先出的原则。如果out
栈不为空,说明之前已经有数据在out
栈中等待出队,不需要从in
栈转移数据。 - 其次,一旦开始转移数据,就要将
in
栈中的数据全部转移完(while (!in.empty())
)。这是因为队列的先进先出特性,要保证先进入队列的数据先出队。
- 首先,
- 在转移数据时,从
in
栈弹出数据(in.pop()
),然后将弹出的数据压入out
栈(out.push()
)。
- 这个方法的目的是将
四、push
方法(入队操作)
- 入队操作
- 在
push
方法中,首先将元素x
压入in
栈(in.push(x)
)。 - 然后调用
inToOut
方法,这个调用的目的是为了在入队操作后,检查是否需要将in
栈中的数据转移到out
栈中,以保持队列的顺序。
- 在
五、pop
方法(出队操作)
- 出队操作
- 首先调用
inToOut
方法,确保数据在正确的栈中。如果out
栈为空,这个方法会将in
栈中的数据转移到out
栈中。 - 然后从
out
栈弹出一个元素(return out.pop()
),这模拟了队列的出队操作,即取出最先进入队列的元素。
- 首先调用
六、peek
方法(查看队首元素操作)
- 查看队首元素操作
- 同样先调用
inToOut
方法,保证数据顺序正确。 - 然后返回
out
栈的栈顶元素(return out.peek()
),这个操作只是查看队首元素,而不将其从队列中移除。
- 同样先调用
七、empty
方法(判断队列是否为空操作)
- 判断队列是否为空操作
- 这个方法通过检查
in
栈和out
栈是否都为空(return in.isEmpty() && out.isEmpty()
)来判断整个队列是否为空。如果两个栈都为空,说明队列中没有元素。
- 这个方法通过检查
代码实现
//利用栈实现队列
// 测试链接 : https://leetcode.cn/problems/implement-queue-using-stacks/
class MyQueue {
public Stack<Integer> in;
public Stack<Integer> out;
public MyQueue() {
in = new Stack<Integer>();
out = new Stack<Integer>();
}
// 倒数据
// 从in栈,把数据倒入out栈
// 1) out空了,才能倒数据
// 2) 如果倒数据,in必须倒完
private void inToOut() {
if (out.empty()) {
while (!in.empty()) {
//将in中弹出的数据压入out中
out.push(in.pop());
}
}
}
public void push(int x) {
in.push(x);
inToOut();
}
public int pop() {
inToOut();
return out.pop();
}
public int peek() {
inToOut();
return out.peek();
}
public boolean empty() {
return in.isEmpty() && out.isEmpty();
}
}
二.利用队列实现栈
1.题目:用队列实现栈
算法原理
一.push操作原理
- 当执行
push
操作时,首先记录当前队列queue
的大小n
。 - 然后将新元素
x
添加到队列末尾。 - 接着,通过循环
n
次,每次将队列头部的元素取出并重新添加到队列末尾。这样做的目的是将新添加的元素x
移动到队列的头部,从而模拟栈的后进先出(LIFO)特性。因为经过这一系列操作后,新元素x
成为了队列中最先被取出的元素,就像栈顶元素一样。
二.pop操作原理
pop
操作直接调用队列的poll
方法。由于push
操作已经将新元素移动到队列头部(如果是最后一个被push
进去的元素),所以poll
操作会取出这个相当于栈顶的元素,符合栈的弹出操作逻辑。
三.top操作原理
top
操作调用队列的peek
方法。peek
方法返回队列头部的元素但不删除它,由于push
操作保证了最后push
进去的元素在队列头部,所以这个操作返回的就是相当于栈顶的元素。
四.empty操作原理
empty
操作直接调用队列的isEmpty
方法,用于判断栈是否为空。因为这个基于队列实现的栈的数据都存储在队列中,所以当队列空时,栈也是空的。
代码实现
class MyStack {
Queue<Integer> queue;
public MyStack() {
queue = new LinkedList<Integer>();
}
// O(n)
public void push(int x) {
int n = queue.size();
queue.offer(x);
for (int i = 0; i < n; i++) {
queue.offer(queue.poll());
}
}
public int pop() {
return queue.poll();
}
public int top() {
return queue.peek();
}
public boolean empty() {
return queue.isEmpty();
}
}