剑指Offer9——使用双栈模拟队列

剑指Offer9——使用双栈模拟队列

队列Queue是具有FIFO(First in First out)特性的数据结构,栈Stack是具有LIFO(后进先出)特性的数据结构。下面提供一种思路使用双栈来模拟队列。

1. 思路——为何需要用两个栈?

很显然一个普通的栈是无法替代队列的,这是因为先进栈的元素总是后出栈。

如果输入序列是123(假设push和pop不交替进行),输出序列仅为321,与队列恰好是反过来的。那么,我们产生了一个思路,就像是“负负得正”一样,如果增加一个栈来接收上一个栈所pop出的元素,其输出序列就像一个队列一样。这说明使用两个栈模拟队列在理论上是可行的,但是还有一些细节需要注意。(见实现过程)

2. 实现过程叙述

首先我们设置两个栈:inStack和outStack。

当进行入队操作时,直接将入队元素push进inStack。

当进行出队操作时,这里需要进行一些判断:outStack中的元素是来自于inStack,但是不是说元素进入inStack后直接pop并输出到outStack,因为如果outStack内存在元素,其一定要先于目前在inStack内元素输出,如果现在就直接把inStack内元素pop并输出到outStack中会导致元素顺序混乱(不符合FIFO),因此这里要注意:一定要在outStack为空的前提下再从inStack向其输出元素。也就是说若outStack内有元素就先弹出,若没有则先从inStack内弹出并压入outStack栈,再从outStack栈弹出。这个过程体现在CQueue的deleteHead方法中。

3. 代码示例

class CQueue {
    // 推荐使用双端队列模拟栈
    private Deque<Integer> inStack;
    private Deque<Integer> outStack;
    
    public CQueue() {
        // 此处使用菱形语法,也可以在菱形内补充Integer
        inStack = new ArrayDeque<>();
        outStack = new ArrayDeque<>();
    }
    
    // 直接push进inStack就好
    public void appendTail(int value) {
        inStack.push(value);
    }
    
    public int deleteHead() {
        /** 此处为代码的关键
         ** 只有当outStack为空且inStack不为空时操作将inStack元素转移进outStack
         ** 否则会导致顺序变乱
         */
        if(outStack.isEmpty()) {
            while (!inStack.isEmpty()) {
            outStack.push(inStack.pop());
            }
        }
        if (!outStack.isEmpty()) return outStack.pop();
        // 如果outStack为空,返回-1
        return -1;
    }
}

/**
 * Your CQueue object will be instantiated and called as such:
 * CQueue obj = new CQueue();
 * obj.appendTail(value);
 * int param_2 = obj.deleteHead();
 */
posted @ 2022-03-27 21:10  IamQisir  阅读(62)  评论(0编辑  收藏  举报