栈和队列常考笔试题(二)

本文详细讲解了如何使用队列实现栈的基本操作,包括push、pop、top和empty,以及如何设计和实现循环队列,涵盖MyCircularQueue的构造、入队、出队、获取队首和队尾元素、检查队列是否为空或已满等关键功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、使用队列实现栈的下列操作

push(x) – 元素 x 入栈
pop() – 移除栈顶元素
top() – 获取栈顶元素
empty() – 返回栈是否为空

思路:
先创建一个队列,用队列实现入栈操作很简单,直接在队列的末尾增加元素就可以:
在这里插入图片描述
pop操作移除栈顶元素相对来说比较复杂,在上面那个示例中,栈顶元素是5,在最右边,而出队列又只能在最左边进行,要移除5这个元素,我们首先得把前面的4个元素出队列,再尾插到队列中,这样一来5就在最左边,最后出掉队首元素,也就是移除了栈顶元素。
在这里插入图片描述
top操作获取栈顶元素跟pop操作的过程基本是一样的,需要注意的是,我们查看了栈顶元素5之后,必须把5出队列,然后再尾插到队列中,恢复栈中数据原来的样子,避免出错。
empty操作查看栈是否为空也就是看当前队列是否为空。
直接看代码:

class MyStack {

        private LinkedList<Integer> queue;

        /**
         * Initialize your data structure here.
         */
        public MyStack() {
            this.queue = new LinkedList<Integer>();
        }

        /**
         * Push element x onto stack.
         */
        public void push(int x) {
            this.queue.addLast(x);
        }

        /**
         * Removes the element on top of the stack and returns that element.
         */
        public int pop() {
            //出栈的时候,把前面的数据(size-1)出栈再尾插到队尾,最后出掉最后一个元素
            int size = this.queue.size();
            for (int i = 0; i < size - 1; i++) {
                int v = this.queue.get(0);
                this.queue.remove(0);
                this.queue.addLast(v);
            }
            int v = this.queue.get(0);
            this.queue.remove(0);
            return v;
        }

        /**
         * Get the top element.
         */
        public int top() {
            int size = this.queue.size();
            for (int i = 0; i < size - 1; i++) {
                int v = this.queue.get(0);
                this.queue.remove(0);
                this.queue.addLast(v);
            }
            int v = this.queue.get(0);
            this.queue.remove(0);
            this.queue.addLast(v);
            return v;
        }

        /**
         * Returns whether the stack is empty.
         */
        public boolean empty() {
            return this.queue.size() == 0;
        }
    }

2、设计一个循环队列
要求:

MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。

思路:

  • enQueue(value)入队列,如果队列已满,返回false,否则的话将数据放入rear指向的位置,然后将rear引用指向下一个可用的位置,注意数组越界的情况,依然使用 (rear+1) % length ,最后把队列的大小+1。
    代码如下:
public boolean enQueue(int value) {
            if (this.size == this.array.length){
                return false;
            }
            this.array[this.rear] = value;
            this.rear = (this.rear+1)%this.array.length;
            this.size++;
            return true;
}
  • deQueue()出队列,如果队列为空,返回false,否则的话将front引用指向下一个位置,还是要考虑数组越界的情况,最后将队列大小减1.
    代码如下:
public boolean deQueue() {
            if (this.size==0){
                return false;
            }
            this.front = (this.front+1) % this.array.length;
            this.size--;
            return true;
}
  • Front()获取队列的头并返回,如果队列为空,返回-1,否则返回front引用保存的数据。
    代码如下:
public int Front() {
            if (this.size==0){
                return -1;
            }
            return this.array[this.front];
}
  • Rear()获取队尾的元素,如果队列为空,返回-1,否则要去寻找队尾元素,注意,队尾元素并不是rear引用的指向。
    通常情况下,rear-1的位置就是队尾元素,但是如果是下面这种特殊情况,直接减1会数组越界。
    在这里插入图片描述
    按照数学的思维,我们可以使用 (this.rear-1+this.array.length)%this.array.length 来处理这种特殊情况。
    代码如下:
public int Rear() {
            if (this.size==0){
                return -1;
            }
            int index = (this.rear-1+this.array.length)%this.array.length;
            return this.array[index];
}

还有一种简单的方法,观察上图可以看出,只有当rear==0的时候会出现特殊情况,而这时它的队尾元素在数组下标为7的位置,其他情况rear-1的位置就是队尾元素,所以我们可以采用三目运算符来处理这种特殊情况。
代码如下:

public int Rear2(){
            if (this.size==0){
                return -1;
            }
            int index = this.rear==0?this.array.length-1:this.rear-1;
            return this.array[index];
}
  • 检查队列是否为空,有两种方法,一种是直接判断队列的大小等不等于0,另一种是判断rear是否等于front。
    代码如下:
public boolean isEmpty() {
            return this.size == 0;
}

public boolean isEmpty2() {
            return this.rear == this.front;
}
  • 检查循环队列是否已满,通常情况下,我们认为只要rear+1==front,那么这个循环队列就是满的。而像下图这种极端情况,如果使用rear+1判断,会出现数组越界的情况。
    在这里插入图片描述
    那么要怎么处理呢?按照数学的思想,我们可以采用 (rear+1) % length 的思想,如果 (rear+1) % length == front,说明循环队列是满的,这样也不会有数组越界的情况。
    代码如下:
public boolean isFull2(){
            if ((this.rear+1)%this.array.length == this.front){
                return true;
            }
            return false;
 }

也可以直接使用队列大小与数组大小相比较来判断循环队列是否已满。

public boolean isFull() {
            return this.size==this.array.length;
}

完整代码在我的Github上:
https://github.com/Nanfeng11/DataStructure/blob/master/queue/src/main/java/com/nanfeng/Interview.java

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值