使用两个队列实现栈

使用两个 队列实现栈

参考文章

栈的队列的特点

栈和队列都是用来保存数据的,无论底层是使用数组还是链表来实现,其基本原理是不变的,那就是栈的特点的先进后出,队列的特点是先进先出。

队列的常用方法

  • isEmpty()

    • 判断队列是否为空
  • size()

    • 返回队列中元素的个数
  • enqueue()

    • 向队列中插入数据
  • dequeue()

    • 从队列中弹出数据并返回
  • peek()

    • 返回队列中第一个数据

使用队列来实现栈
使用队列来实现栈的方式其实和通过栈实现队列的方式差不多。用以上方法也是可以的。但是,为了让大家更好的掌握这两种数据结构,再给大家提供另外一种思路。

上面的队列实现中。插入方法并没有额外的操作,只是在弹出的时候需要做些额度的处理。那么另外一个思路就是在插入的时候做些事情,这样在弹出的时候就可以无须额外操作直接弹出了。同样,还是需要两个队列来实现栈。具体如何操作呢?

image

先来定义一下这个栈:

class MyStack {
   queue<int> a;
   queue<int> b;
}

还是通过一张图,看下使用队列实现的栈是如何进行元素的插入的。

image

从上图中可以看出,用来实现栈的两个队列是不区分用途的,也就是说两个队列都具备插入和弹出的功能。之所以可以这么做的原因就是,他要保证任何时候都只有一个队列中有元素。

上图的插入操作,插入H的时候,两个队列都为空,优先选择从queue1插入。 当想要插入O的时候,由于queue1中已经包含了数据,那么就讲O插入queue2中,然后再将queue1中的数据依次插入queue2。实现代码如下:

void push(int x) {
   if (a.empty() && b.empty()) {
       a.push(x);
       return;
   }
   if (a.empty()) {
       a.push(x);
       while (!b.empty()) {
           a.push(b.front());
           b.pop();
       }
   }
   else {
       b.push(x);
       while (!a.empty()) {
           b.push(a.front());
           a.pop();
       }
   }
}

再来一张图,看看如何使用两个队列来实现栈的弹出操作。

image

由于我们在插入的时候,保证了两个队列中只有一个队列包含数据,并且数据的顺序已经调整好了(包含数据的那个队列的队列头就是整个栈的栈顶),那么就直接从有数据的那个队列中往外弹数据就可以了。实现代码如下:

int pop() {
   if (a.empty()) {
       int temp = b.front();
       b.pop();
       return temp;
   }
   else {
       int temp = a.front();
       a.pop();
       return temp;
   }
}

好了,至此,我们已经完成了使用两个栈实现队列和两个队列实现栈的功能的介绍。总结一下,主要有两种方案。拿通过栈来实现队列举例。

  1. 方案一:定义两个栈,一个专门用来插入,一个专门用来弹出。插入操作只会插入到插入栈。弹出的时候,优先从弹出栈往外弹,如果弹出栈中的内容为空,那么就将插入栈中的数据依次弹出,并压入弹出栈,然后再弹出。

  2. 方案二:定义两个栈,不区分作用,但是有一个原则就是始终要保证其中一个栈为空。每次插入的时候先将待插入数据直接插入到空的栈中,然后再将另外一个栈中的数据依次弹出,并压入这个刚刚插入新数据的栈中。弹出的时候,只要从那个有数据的栈中往外弹数据就可以了。

无论以上哪种方案,其实根本原理都是和我们小时候玩的汉诺塔游戏差不多。

猜你喜欢

转载自blog.csdn.net/kato_op/article/details/80214639