剑指OFFER笔记_09_用两个栈实现队列_JAVA实现
题目:用两个栈实现队列
- 用两个栈实现一个队列。队列的生命如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入节点和再队列头部删除节点的功能。
解题思路
- 栈的特点是:先进后出,后进先出。
- 队列的特点时:先进先出,后进后出。
- 栈的特点是和队列相反的,题目给了我们两个栈,我们是不是可以利用入第一个栈后在出栈入第二个栈的操作让栈中的顺序颠倒,从而实现和队列一样的效果?
- 两个栈分别具有空和非空两种状态,组合起来就是4种情况,在情况分析中将会找出这四种情况下实现入队和出队的方法。
情况分析
- stack1和stack2都为空。
如果要appendTail,可以直接往stack1中加入元素。
如果要deleteHead,返回-1即可,因为没有元素可以删除。 - stack1不为空,stack2为空。
如果要appendTail,可以直接往stack1中加入元素。
如果要deleteHead,我们应当返回1,但是从stack1中无法直接取得。我们可以将stack1整体移到stack2中,此时stack2顶端元素就是我们需要的元素。
- 此时也就形成了第三种状况:stack1为空,stack2不为空。
如果要appendTail,可以直接往stack1中加入元素。
如果要deleteHead,也可以直接从stack2中取出顶端元素。
- 此时形成了最后一种情况,stack1和stack2都不为空。
如果要appendTail,可以直接往stack1中加入元素。
如果要deleteHead,直接从stack2中取出即可。
- 总结四种情况,可以归纳为如下规律:
- appendTail:直接往stack1中push即可,不需考虑各种情况。
- deleteHead:若stack2不为空,直接从stack2中pop即可;若stack2为空,需要将stack1的元素全部移过来才能执行pop操作(此处需要考虑stack1为空的情况,返回-1报错)。
代码
函数主体部分代码
package q09;
import java.util.Stack;
public class CQueue {
private Stack<Integer> stack1;
private Stack<Integer> stack2;
public CQueue() {
this.stack1 = new Stack<Integer>();
this.stack2 = new Stack<Integer>();
}
public void appendTail(int value) {
stack1.push(value);
}
public int deleteHead() {
//第一种情况,如果stack2是空的,那么把stack1的元素全部移过来
if(stack2.isEmpty())
{
//将stack1取空
while(!stack1.isEmpty())
{
//将stack1顶端元素取出,放入stack2中
stack2.push(stack1.pop());
}
//函数需要删除队列首部元素,所以pop出stack2的顶端元素。
//若stack2中无元素,返回-1报错。
return stack2.isEmpty() ? -1 : stack2.pop();
}else
{
//若stack2中不为空,直接pop即可
return stack2.pop();
}
}
}
测试部分代码
package q09;
public class TestApp {
public static void main(String[] args) {
CQueue queue = new CQueue();
//创建一个1-10的队列
for (int i = 1; i <= 10; i++) {
queue.appendTail(i);
System.out.println("将 " + i + " 放入队列。");
}
System.out.println();
//将此队列元素取出,由于第11个不存在,应当返回-1
for (int i = 1; i <= 11; i++) {
System.out.println("将 " + queue.deleteHead() + " 取出队列。");
}
}
}