由两个栈组成的队列,你玩过嘛?

题目描述

【题目】:
编写一个类,用两个栈实现队列,满足队列的基本操作要求:enqueue(入队)、出队(dequeue),peek:获取队列中对头元素。

【解答】

  1. 栈数据结构的特点是先进后出,而队列数据结构的特点是先进先出。用两个栈正好能把顺序反过来实现类似队列的操作。
  2. 具体实现上是一个栈作为压入数据栈,在压入数据栈时,只往这个栈中压入数据(入队),记为 stackPush,另一个栈只作为弹出栈,在弹出数据(出队)只从这个栈弹出,记为 stackPop。
  3. 因为数据压入栈的时候,顺序时先进后出的。那么只要把 stackPush 的数据再压入 stackPop 中,顺序就变回来了。

【举个栗子】
把 1~5 依次压入 stackPush ,那么从stackPush 的栈顶的栈底为 5~1 ,此时再将 5~1 倒stackPop,那么从 stackPop 的栈顶到栈底就变成了 1~5.再从 stackPop 弹出时,顺序就像队列一样,如图所示:

 

听起来貌似简单,但实际上必须做到以下两点:
1.如果 stackPush 要往 stackPop 中压入数据,那么必须一次性把 stackPush 中的数据全部压入。
2.如果 stackPop 不为空,stackPush 绝对不能向 stackPop 中压入数据。

违反了以上两点,都会发生错误。

  • 违反 1 的情况举例:1~5 依次次压入stackPush,stackPush 的栈顶到栈底为 5~1,从 stackPush 压入 stackPop 时,如果只将 5 和 4 压入了 stackPop ,stackPush 还剩下 1、2、3 没有压入。此时如果用户想进行出队操作,那么 4 将最先弹出,与预想的队列顺序就不一致。
  • 违反 2 的情况举例:1~5 依次压入 stackPush,将 stackPush 中的所有数据压入了 stackPop ,此时从 stackPop 栈顶到栈底为 1~5。此时,又有 6~10 压入 stackPop ,这时候stackPop 不为空不能压入数据,如果违反2,向 stackPop 压入数据,stackPop 栈顶到栈底为 6~10,1~5,此时用户如果想进行出队操作,那么 6 将最先弹出,又与预想的队列顺序不一致。

代码实现

上述介绍了压入数据的注意事项。具体实现参看如下代码:

 1public class TwoStackQueue {
 2    private Stack<Integer> stackPush;
 3    private Stack<Integer> stackPop;
 4
 5    public TwoStackQueue() {
 6        stackPush = new Stack<Integer>();
 7        stackPop = new Stack<Integer>();
 8    }
 9
10    //TODO:入队操作,往队列中添加数据
11    public void enqueue(int newData) {
12        this.stackPush.push(newData);
13    }
14
15    //TODO:出队操作,从队列中获取数据,注意队列数据结构是先进先出
16    public int dequeue() {
17        if (stackPush.empty() && stackPop.empty()) {
18            throw new RuntimeException("Queue is empty!");
19        } else if (stackPop.empty()) {
20            while (!stackPush.empty()) {
21                this.stackPop.push(this.stackPush.pop());
22            }
23        }
24        return stackPop.pop();
25    }
26
27    //TODO:获取队列中的队头元素
28    public int peek() {
29        if (stackPush.empty() && stackPop.empty()) {
30            throw new RuntimeException("Queue is  empty!");
31        }else if (stackPop.empty()) {
32            while (!stackPush.empty()) {
33                this.stackPop.push(this.stackPush.pop());
34            }
35        }
36        return stackPop.peek();
37    }
38}

本段代码是在在调用 dequeue 和 peek 方法时进行压入数据的过程。这个压入数据的操作选择的时机可以有很多,调用 enqueue、dequeue 和 peek 三种方法中的任何一种时发生压入数据的行为都是可以的。只要不违反上述两点,就不会出错。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章