一:概述

面试题目:用栈来模拟一个队列,要求实现队列的两个基本操作:入队和出队。

二:具体说明

<1>栈和队列的基本概念及其特点

栈:又名堆栈,它是一种运算受限的线性表。限定在表尾进行插入和删除操作的线性表。一端被称为栈底,另一端被称为栈顶。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素,从一个栈删除元素又被称为出栈或者退栈,它是吧栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

特点:后进先出(Last In First Out)的线性表,简称LIFO表。

队列:是一种特殊的线性表,特殊之处在于它是允许在表的前端(front)进行删除操作,而在后端(rear)进行插入操作,和栈一样,队列是一种操作受限的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

特点:先进先出(First In First Out)的线性表,简称FIFO表。

<2>面试算法的解题思路

栈的特点是后进先出,出入元素都在同一端(栈顶)

入栈:

java面试算法题:如何使用栈去实现队列_时间复杂度

出栈:

java面试算法题:如何使用栈去实现队列_入栈_02

队列的特点是先入先出,出入元素是在不同的两端(队头和队尾)

入队:

java面试算法题:如何使用栈去实现队列_时间复杂度_03

出队

java面试算法题:如何使用栈去实现队列_入栈_04

既然我们拥有两个栈,那么可以让其中一个栈作为队列的入口,负责插入新元素,另一个栈作为队列的出口,负责移除老元素。

java面试算法题:如何使用栈去实现队列_时间复杂度_05

java面试算法题:如何使用栈去实现队列_时间复杂度_06

队列的主要操作无非是两个:入队和出队。

在模拟入队操作时,每一个新元素都被压入到栈A中。

让元素1入队

java面试算法题:如何使用栈去实现队列_出队_07

让元素2入队

java面试算法题:如何使用栈去实现队列_时间复杂度_08

让元素3入队。

java面试算法题:如何使用栈去实现队列_入栈_09

这时,我们希望最先入队的元素1出队,需要怎么做呢?让栈A中的所有元素按顺序出栈,再按照出栈顺序压入栈B。这样一来,元素从栈A弹出并压入栈B的顺序是3、2、1和当初入栈A的顺序1、2、3是相反的。

java面试算法题:如何使用栈去实现队列_入栈_10

此时,让元素1出队,也就是元素1从栈B中弹出。

java面试算法题:如何使用栈去实现队列_出队_11

让元素2出队。

java面试算法题:如何使用栈去实现队列_时间复杂度_12

让元素4入队。

java面试算法题:如何使用栈去实现队列_入栈_13

java面试算法题:如何使用栈去实现队列_入栈_14

此时,出队操作仍然从栈B中弹出元素。让元素3出队

java面试算法题:如何使用栈去实现队列_时间复杂度_15

最后只要栈A中还有元素,就像刚才一样,把栈A中的元素弹出并压入栈B即可

java面试算法题:如何使用栈去实现队列_出队_16

让元素4出队。

java面试算法题:如何使用栈去实现队列_出队_17

总结:

入队操作的时间复杂度显然是O(1)。至于出队操作,如果涉及栈A和栈B元素迁移,那么一次出队的时间复杂度是O(n);如果不用迁移,时间复杂度是O(1).关于这个出队的时间复杂度,这里涉及一个新概念,叫作均摊时间复杂度。需要元素迁移的出队操作只有少数情况,并且不可能连续出现,其后的大多数出队操作都不需要元素迁移。所以把时间均摊到每一次出队操作上面,其时间复杂度是O(1)

<3>代码实现

public class StackQueue {
      private Stack<Integer> stackA = new Stack<Integer>();
      private Stack<Integer> stackB = new Stack<Integer>();


      /**
       * 入队操作:
       * @param element:入队的元素
       */
         public void enQueue(int element){
               stackA.push(element);
         }

      /**
       * 出队操作
       * @return 出栈的元素
       */
      public Integer deQueue() {
          if(stackB.isEmpty()) {
                if(stackA.isEmpty()) {
                      return null;
                }
                // 将栈A中的元素转移到栈B
                transfer();
          }
           return stackB.pop();
         }

      /**
       *  栈A元素转移到栈B
       */
      public void transfer() {
               while(!stackA.isEmpty()) {
                     stackB.push(stackA.pop());
               }
      }

  public static void main(String[] args) {
            StackQueue stackQueue = new StackQueue();
            stackQueue.enQueue(1);
            stackQueue.enQueue(2);
            stackQueue.enQueue(3);
            System.out.println(stackQueue.deQueue());
            System.out.println(stackQueue.deQueue());
            stackQueue.enQueue(4);
            System.out.println(stackQueue.deQueue());
            System.out.println(stackQueue.deQueue());
  }

}