题目:
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入结点和队列头部删除结点的功能。
template<typename T> class CQueue{
public:
CQueue(void);
~CQueue(void);
void appendTail(Const T& node);
T deleteHead();
private:
Stack<T> stack1;
Stack<T> stack2;
};
知识点:
栈是一个非常常见的数据结构,计算机操作系统会给每个线程创建一个栈用来存储函数调用时各个函数的参数、返回地址及临时变量等。栈的特点:先进后出;通常栈是一个不考虑排序的数据结构,我们需要O(n)的时间才能找到其中最大或者最小的元素。如果想在O(1)时间内找到栈中最大或者最小的值,需要栈元素在进栈是就有顺序的存放。
队列也是一个非常常见的数据结构,队列的特点是先进先出;在树的宽度优先遍历算法中,我们在遍历某一层树的结点时,把结点的子结点放到一个队列里,以备下一层结点的遍历。
思路:
在看到由两个栈实现一个队列,我马上想到必须有一个栈负责元素的进栈操作,另一个栈去负责元素的出栈操作;故要有栈实现队列进队和出队操作,必须要有一个栈去负责进队列,另一个栈负责出队列。(假设两个栈命名为stack1、stack2)。
实现队列添加元素:当添加元素时,由stack1负责接收添加的元素。
实现队列删除元素:首先需要分析stack2中不为空时,在stack2中的栈顶元素是最先进入队列的元素,可以弹出。如果stack2为空时,我们把stack1中的元素逐个弹出并压入stack2。由于先进入队列的元素被压到stack1的底端,经过弹出和压入之后就处于stack2的顶端了,又可以直接弹出。
代码实现:
方法一:
public class Main {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
//进栈操作呢
public void appendTail(int item){
stack1.push(item);
}
//出栈操作
public int deleteHead(){
while(!stack2.isEmpty()){
return stack2.pop();
}
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
return stack2.pop();
}
}
方法二:
public class Main {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void appendTail(int item){
stack1.push(item);
}
public int deleteHead() throws Exception{
if(stack2.size() <= 0){
while(stack1.size() > 0){
int data = stack1.pop();
stack2.push(data);
}
}
if(stack2.size() == 0){
throw new Exception("Queue is empty.");
}
int head = stack2.pop();
return head;
}
}
测试:
public static void main(String[] args) {
Main m = new Main();
m.appendTail(1);
m.appendTail(2);
m.appendTail(3);
System.out.println(m.deleteHead());
m.appendTail(4);
System.out.println(m.deleteHead());
m.appendTail(5);
System.out.println(m.deleteHead());
System.out.println(m.deleteHead());
System.out.println(m.deleteHead());
}
小结:
这道由栈实现队列,其实首先考查了我们队栈和队列的理解,栈的先进后出和队列的先进先出;
小思:
这道题是由两个栈实现一个队列;我们可以思考一下由两个队列怎么实现一个栈的操作。
思路:
模拟栈的入栈操作:如果两个队列都为空,优先选择队列1添加元素,否则,哪个队列有元素,就在哪个队列尾部追加元素。
模拟栈的出栈操作:如果两个队列都为空,抛出异常;否则,模拟栈的出栈规则,后进先出,即将其中一个不为空的队列的前n-1个元素从当前队列删除,添加入另一个队列中,再把此队列剩余的最后一个元素删除。故模拟栈的出栈操作。
public class Main2 {
Queue<Integer> queue1 = new LinkedList<Integer>(); //Queue是接口,故不能直接实例化
Queue<Integer> queue2 = new LinkedList<Integer>();
//模拟栈压入数据
public void push(int item){
//如果queue1队列和queue2队列都为空,优先选择queue1队列添加元素
if(queue1.isEmpty() && queue2.isEmpty()){
queue1.add(item);
return;
}
//如果队列1为空,向队列2添加元素
if(queue1.isEmpty()){
queue2.add(item);
return;
}
//如果队列2为空,向队列1添加元素
if(queue2.isEmpty()){
queue1.add(item);
return;
}
}
//模拟栈出数据
public int pop(){
//如果两个队列都没有元素可以弹出异常
if(queue1.isEmpty() && queue2.isEmpty()){
try {
throw new Exception("栈为空!");
} catch (Exception e) {
e.printStackTrace();
}
}
//如果queue1为空,将queue2的前queue2.size()-1个元素弹出放入queue1队列,queue2的最后一个元素直接弹出
if(queue1.isEmpty()){
while(queue2.size() > 1){
queue1.add(queue2.poll());
}
return queue2.poll();
}
//如果queue2为空,将queue1的前queue1.size()-1个元素弹出放入queue2队列,queue1的最后一个元素直接弹出
if(queue2.isEmpty()){
while(queue1.size() > 1){
queue2.add(queue1.poll());
}
return queue1.poll();
}
return 0;
}
}