栈和队列相互实现

背景

一道很经典的数据结构的题目实现。

栈:一般是后进先出的顺序,可以看下java中的Stack这个类。

队列:一般是先进先出的顺序,但是java中的Queue接口中也写了注释,没有要求是必须严格的先进先出,比如java中也有优先级队列、双端队列Deque。

代码实现

在代码的注释中有描述对应的思路,这里不去赘述

  • 两个栈实现队列
/**
 * Created by zlj on 2020/3/18.
 * 两个栈 实现 队列
 *
 * 思路:
 * 1.入栈:直接压栈进入stackOne
 * 2.出栈:
 *      (1)判断stackOne是否为空,如果不为空,则将stackOne中的数据导入stackTwo。取出stackTwo弹栈的元素
 *      (2)判断stackTwo是否为空,如果不为空,重复(1)操作
 *
 */
public class StackToQueue<T> {

    Stack<T> stackOne = new Stack<>();
    Stack<T> stackTwo = new Stack<>();

    /**
     * 入队
     * @param data
     */
    private void push(T data) {
        stackOne.push(data);
    }

    /**
     * 出队列
     * @return
     */
    private T pop() {
        if (stackOne.empty() && stackTwo.empty())
            return null; // 容错 栈的pop方法如果没有元素了会报错
        // 其实加不加这个判断相当于Queue接口中poll(做了容错) 和 remove(没做容错) 两个方法的区别

        while (!stackOne.isEmpty()) {
            // 弹栈到stackTwo
            stackTwo.push(stackOne.pop());
        }

        // 这时弹栈 stackTwo中的元素
        T stackTwoFirstEmt = stackTwo.pop();

        // 如果出队列的时候元素都在stackTwo
        while(!stackTwo.isEmpty()) {
            // 数据倒回stackOne 以便下一次pop的时候 再利用栈的特性 实现队列出队的顺序
            stackOne.push(stackTwo.pop());
        }

        return stackTwoFirstEmt;
    }

    public static void main(String[] args) {
        StackToQueue<Integer> stackToQueue = new StackToQueue<>();

        // 队列入队
        Stream.iterate(1, i -> i+1).limit(10).forEach(stackToQueue::push);

        // 队列出队
        for(int i = 0; i< 10000; i++) {
            Integer pop = stackToQueue.pop();
            if (pop == null) break;
            System.out.println("队列出队:" + pop);
            try {
                Thread.sleep(200);
            } catch (Exception e) {

            }

        }
    }

}

  • 两个队列实现栈
/**
 * Created by zlj on 2020/3/19.
 * 两个队列实现栈
 * 思路: 维护两个队列 Q1 和 Q2
 * (1)入栈:即为队列Q1中加入元素
 * (2)出栈: 关键就是保持队列q1和q2一直有一个为空
 *
 *          - 首先元素入q1,队列中为 [tail]xn->xn-1...->x1 [head]  这时将q1中的n-1个元素入q2 q2中元素: [tail] xn-1->xn-2...->x1 [head]
 *          - xn从q1中出队
 *          - 这时q1为空,q2有n-1个元素,重复第一步,只不过现在是将q2中的n-2个元素出队放入q1中,再将q2中的xn-1出队即可。
 *          - 重复操作直到 q1和q2都为空为止
 */
public class TwoQueueToStack<T> {

    // 这里用的Deque 虽然只是需要的是队列 先进先出(FIFO)的特性 但其实Deque既提供了stack的操作、又提供了queue的操作,也提供了对first和end的操作(LinkedList里面叫做head和tail)
    Queue<T> queue1 = new ArrayDeque<>();
    Queue<T> queue2 = new ArrayDeque<>();

    /**
     * 栈的入栈操作
     * @param element
     */
    void push(T element) {
        queue1.offer(element); // 比add更友好
    }


    /**
     * 栈的出栈操作
     *
     * @return
     */
    T pop() {

        if (!queue1.isEmpty()) {
            while (queue1.size() > 1) {
                // q1出队 入队q2
                queue2.offer(queue1.poll());
            }
            // q1的size是1了
            return queue1.poll();
        }

        if (!queue2.isEmpty()) {
            while (queue2.size() > 1) {
                queue1.offer(queue2.poll());
            }
            // q2的size是1了
            return queue2.poll();
        }

        return null;
    }

    int size() {
        if (!queue1.isEmpty()) {
            return queue1.size();
        } else if (!queue2.isEmpty()) {
            return queue2.size();
        }
        return 0;
    }

    /**
     * 实现一个只查看栈顶元素的操作
     * 思路也是先将q1的n-1个元素入队q2,这时将q1中的剩余元素peek出来,不是poll出来(元素不能删除),再将其也导入到q2中
     * // 注意这里如果直接用的是双端队列Deque 其实直接可以在不为空的队列中 peekLast = =
     */
    @SuppressWarnings("all")
    T top() {
        T top = null;
        if (!queue1.isEmpty()) {
          while (queue1.size() > 1) {
              queue2.offer(queue1.poll());
          }
          top = queue1.peek();
          // 再将其入队至q2
            queue2.offer(queue1.poll());
        }

        if (!queue2.isEmpty()) {
            while (queue2.size()>1) {
                queue1.offer(queue2.poll());
            }

            top = queue2.peek();
            queue1.offer(queue2.poll());
        }

        return top;
    }




    public static void main(String[] args) {

        TwoQueueToStack<Integer> twoQueueToStack = new TwoQueueToStack<>();

        // 压栈
        Stream.iterate(1, i -> i+1).limit(10).forEach(twoQueueToStack::push);

        // 查看栈顶的元素
        System.out.println("栈顶元素:" + twoQueueToStack.top());

        // 出栈
        int size = twoQueueToStack.size();
        for (int i = 0; i <size; i++) { // 注意这里不能写成 i < twoQueueToStack.size() 因为循环中的pop操作会减少stack中的元素
            System.out.println("元素出栈" + twoQueueToStack.pop());
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值