队列4:栈实现队列和队列实现栈

Posted 纵横千里,捭阖四方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了队列4:栈实现队列和队列实现栈相关的知识,希望对你有一定的参考价值。

​栈的特点是后进先出,队的特点是先进先出。两个栈将底部拼接到一起就能实现队列的效果, 通过队列也能实现栈的功能。在很多地方能看到让你通过两个栈实现队列的题目,也有很多地方是两个队列实现栈的题目,我们就干脆一次看一下如何做。

这正好对应LeetCode232和225两道题

1.LeetCode232. 用栈实现队列

先看题意:

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):

实现 MyQueue 类:

void push(int x) 将元素 x 推到队列的末尾

int pop() 从队列的开头移除并返回元素

int peek() 返回队列开头的元素

boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

你只能使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。

你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

分析:

这个题的思路是:将一个栈当作输入栈,用于压入 push 传入的数据;另一个栈当作输出栈,用于pop 和 peek 操作。

每次pop 或 peek 时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈,这样输出栈从栈顶往栈底的顺序就是队列从队首往队尾的顺序。

代码难度不算大:

class MyQueue {    Deque<Integer> inStack;    Deque<Integer> outStack;    public MyQueue() {        inStack = new LinkedList<Integer>();        outStack = new LinkedList<Integer>();    }    public void push(int x) {        inStack.push(x);    }    public int pop() {        if (outStack.isEmpty()) {            in2out();        }        return outStack.pop();    }    public int peek() {        if (outStack.isEmpty()) {            in2out();        }        return outStack.peek();    }    public boolean empty() {        return inStack.isEmpty() && outStack.isEmpty();    }    private void in2out() {        while (!inStack.isEmpty()) {            outStack.push(inStack.pop());        }    }}

2.LeetCode225. 用队列实现栈

先看题意:

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

实现 MyStack 类:

void push(int x) 将元素 x 压入栈顶。

int pop() 移除并返回栈顶元素。

int top() 返回栈顶元素。

boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

分析:这个问题首先想到的是使用两个队列来实现。其实还能用一个队列实现,我们分别看一下。

方法一:两个队列

为了满足栈的特性,即最后入栈的元素最先出栈,在使用队列实现栈时,应满足队列前端的元素是最后入栈的元素。可以使用两个队列实现栈的操作,其中 queue1用于存储栈内的元素,queue2作为入栈操作的辅助队列。

入栈操作时,首先将元素入队到 queue2,然后将 queue1的全部元素依次出队并入队到queue2,此时 queue2的前端的元素即为新入栈的元素,再将 queue 

1和queue2互换,则 queue1的元素即为栈内的元素,queue 1的前端和后端分别对应栈顶和栈底。

由于每次入栈操作都确保queue1的前端元素为栈顶元素,因此出栈操作和获得栈顶元素操作都可以简单实现。出栈操作只需要移除queue1的前端元素并返回即可,获得栈顶元素操作只需要获得 queue 1的前端元素并返回即可(不移除元素)。

由于 queue 1用于存储栈内的元素,判断栈是否为空时,只需要判断 queue 

1是否为空即可。

class MyStack {    Queue<Integer> queue1;    Queue<Integer> queue2; public MyStack() {        queue1 = new LinkedList<Integer>();        queue2 = new LinkedList<Integer>();    }    public void push(int x) {        queue2.offer(x);        while (!queue1.isEmpty()) {            queue2.offer(queue1.poll());        }        Queue<Integer> temp = queue1;        queue1 = queue2;        queue2 = temp;    }        public int pop() {        return queue1.poll();    }    public int top() {        return queue1.peek();         public boolean empty() {        return queue1.isEmpty();    }}

方法二:使用一个队列

在网上看到,还可以使用一个队列来实现,一起看看:

使用一个队列时,为了满足栈的特性,即最后入栈的元素最先出栈,同样需要满足队列前端的元素是最后入栈的元素。

入栈操作时,首先获得入栈前的元素个数 n,然后将元素入队到队列,再将队列中的前 n 个元素(即除了新入栈的元素之外的全部元素)依次出队并入队到队列,此时队列的前端的元素即为新入栈的元素,且队列的前端和后端分别对应栈顶和栈底。

由于每次入栈操作都确保队列的前端元素为栈顶元素,因此出栈操作和获得栈顶元素操作都可以简单实现。出栈操作只需要移除队列的前端元素并返回即可,获得栈顶元素操作只需要获得队列的前端元素并返回即可(不移除元素)。

由于队列用于存储栈内的元素,判断栈是否为空时,只需要判断队列是否为空即可。

class MyStack {    Queue<Integer> queue;      public MyStack() {        queue = new LinkedList<Integer>();    }     public void push(int x) {        int n = queue.size();        queue.offer(x);        for (int i = 0; i < n; i++) {            queue.offer(queue.poll());        }    }     public int pop() {        return queue.poll();    }    public int top() {        return queue.peek();    }        public boolean empty() {        return queue.isEmpty();    }} 

以上是关于队列4:栈实现队列和队列实现栈的主要内容,如果未能解决你的问题,请参考以下文章

新手向C语言实现特殊数据结构——队列(含用两个队列实现栈)

新手向C语言实现特殊数据结构——队列(含用两个队列实现栈)

数据结构栈和队列,看完这一篇就够了(万字配动图配习题)

栈和队列的常见题型

用两个队列实现一个栈and用两个栈实现一个队列

用两个栈实现队列的POP和PUSH操作