1. 232 用栈实现队列 E
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(
push
、pop
、peek
、empty
):实现
MyQueue
类:
void push(int x)
将元素 x 推到队列的末尾int pop()
从队列的开头移除并返回元素int peek()
返回队列开头的元素boolean empty()
如果队列为空,返回true
;否则,返回false
1.1 思路分析
-
这是一道模拟题,不涉及到具体算法,考察的就是对栈和队列的掌握程度。
-
使用栈来模式队列的行为,如果仅仅用一个栈,是一定不行的,所以需要两个栈==一个输入栈,一个输出栈==,这里要注意输入栈和输出栈的关系。
-
在push数据的时候,只要数据放进输入栈就好;但在pop的时候,操作就复杂一些,输出栈如果为空,就把进栈数据全部导入进来(注意是全部导入,不然会导致顺序变乱),再从出栈弹出数据,如果输出栈不为空,则直接从出栈弹出数据就可以了。
-
最后如何判断队列为空呢?如果进栈和出栈都为空的话,说明模拟的队列为空了。
-
在代码实现的时候,会发现pop() 和 peek()两个函数功能类似,代码实现上也是类似的,可以思考一下如何把代码抽象一下。
1.2 解题代码
class MyQueue {
Stack<Integer> stackIn;
Stack<Integer> stackOut;
public MyQueue() {
stackIn = new Stack<>();//负责进栈
stackOut = new Stack<>();//负责出栈
}
public void push(int x) {
stackIn.push(x);
}
public int pop() {
dumpStackIn();
return stackOut.pop();
}
public int peek() {
dumpStackIn();
return stackOut.peek();
}
public boolean empty() {
//判断是否为空:若in不空,out为空:false&&true=false,即不空
return stackIn.isEmpty()&& stackOut.isEmpty();
}
private void dumpStackIn(){
if (!stackOut.isEmpty()) {
return;
}
while (!stackIn.isEmpty()) {
stackOut.push(stackIn.pop());
}
}
}
1.3 总结及注意
- pop() 和 peek()两个函数功能类似,可以单独把他们共用的部分抽象出来构造一个新的函数,比如此题中新创建的dumpStackIn()函数。
- 本题不涉及什么高深的算法知识,就是用两个栈模拟队列的行为;
2. 225 用队列实现栈 E
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(
push
、top
、pop
和empty
)。实现
MyStack
类:
void push(int x)
将元素 x 压入栈顶。int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的,返回true
;否则,返回false
。
2.1 思路分析
用一个队列进行模拟,将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时弹出元素顺序就是栈的顺序。
2.2 解题代码
class MyStack {
Queue<Integer> queue;
public MyStack() {
queue=new LinkedList<>();
}
public void push(int x) {
queue.add(x);
}
//移出并返回
public int pop() {
rePositon();
return queue.poll();
}
//返回栈顶
public int top() {
//把前面的元素都移出
rePositon();
//队列函数poll 返回队首元素并删除
int result=queue.poll();
//重新添加回去
queue.add(result);
return result;
}
public boolean empty() {
return queue.isEmpty();
}
private void rePositon(){
int size= queue.size();
size--;
while (size-- > 0) {
queue.add(queue.poll());
}
}
}
3. 栈和队列方法汇总
3.1 栈
- push():在栈的顶部插入一个元素。
- pop():返回栈顶元素,并将其删除。
- peek():返回栈顶元素,但是不会将其删除。
- empty():判断栈是否为空,如果为空则返回true,否则返回false。
- search(Object o):返回元素在栈中的位置,如果元素不存在,则返回-1。
这些方法常用于实现基于栈的数据结构,如表达式求值、回文字符串判断等。在使用栈的方法时,应将栈声明为具体的类,如Stack、ArrayDeque等。需要注意的是,由于LinkedList实现了Deque接口,因此它也可以用来作为栈的实现。
3.2 队列
- offer():将元素插入队尾,返回是否成功插入。
- add():为队列插入元素,如果队列已满,则抛出IllegalStateException异常。
- element():返回队列头部的元素,但是不会将其删除。
- peek():返回队列头部的元素,但是不会将其删除。如果队列为空,则返回null。
- poll():返回队列头部的元素并将其删除,如果队列为空,则返回null。
- remove():返回队列头部的元素并将其删除。如果队列为空,则抛出NoSuchElementException异常。
- size():返回队列中元素的数量。
这些方法常用于实现基于队列的数据结构,如生产者-消费者模型等。注意,在使用队列方法时,应将队列声明为具体的类,如LinkedList、ArrayDeque等。
PS:
在Java中,队列的方法中有两个方法可以用于添加元素,一个是offer(Object o)
方法,另一个是add(Object o)
方法,两者在功能上有一些不同。具体来说:
offer(Object o)
方法将指定的元素插入到队列的末尾,如果队列已满,则返回false,否则返回true。add(Object o)
方法也将指定的元素插入到队列的末尾,但是如果队列已满,则抛出IllegalStateException异常。
因此,offer(Object o)
方法通常用于具有限制容量的队列,如阻塞队列或有大小限制的队列,因为该方法可以返回一个表示是否成功插入元素的布尔值。而add(Object o)
方法则不适用于具有限制容量的队列,因为如果在队列满的情况下使用add()方法,则会引发异常。
综上所述,如果对于具有容量限制的队列而言,如果必须确保元素被添加到队列中,则应使用add(Object o)
方法;如果可以容忍失败的情况,则可以使用offer()
方法。而对于不是限制容量的队列,例如LinkedList,两个方法没有任何功能上的差异。
3.3 比较
方法 | 栈 | 队列 |
---|---|---|
添加元素 | push() | offer() |
返回元素,并删除 | pop() | poll() |
返回元素但不删除 | peek() | peek() |
判断为空 | empty() | isEmpty() |
获取元素数 | 不适用 | size() |
查找元素位置 | search(Object o) | 不适用 |