栈和队列之队列

队列(Queue)

概念

队列 :只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为 队尾( Tail/Rear 出队列:进行删除操作的一端称为 队头 Head/Front
队列和栈的区别为一个是先进先出,一个是先进后出!!

队列的使用

方法功能
boolean offer(E e)入队列
peek()
获取队头元素
int size()获取队列中有效元素个数
boolean isEmpty()
检测队列是否为空
E poll()
出队列

示例代码如下:

public static void main(String[] args) {
Queue<Integer> q = new LinkedList<>();
q.offer(1);
q.offer(2);
q.offer(3);
q.offer(4);
q.offer(5); // 从队尾入队列
System.out.println(q.size());
System.out.println(q.peek()); // 获取队头元素
q.poll();
System.out.println(q.poll()); // 从队头出队列,并将删除的元素返回
if(q.isEmpty()){
System.out.println("队列空");
}else{
System.out.println(q.size()

队列模拟实现

双向链表实现:

public class Queue {

public static class ListNode{
ListNode next;
ListNode prev;
int value;
ListNode(int value){
this.value = value;
}
}
ListNode first; 
ListNode last; 
int size = 0;

public void offer(int e){
ListNode newNode = new ListNode(e);
if(first == null){
first = newNode;
// last = newNode;
}else{
last.next = newNode;
newNode.prev = last;
// last = newNode;
}
last = newNode;
size++;
}

public int poll(){
int value = 0;
if(first == null){
return null;
}else if(first == last){
last = null;
first = null;
}else{
value = first.value;
first = first.next;
first.prev.next = null;
first.prev = null;
}
--size;
return value;
}

public int peek(){
if(first == null){
return null;
}
return first.value;
}
public int size() {
return size;
}
public boolean isEmpty(){
return first == null;
}
}

单向链表实现:

public class MyQueue {
    static class ListNode {
        public int val;
        public ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }

    ListNode head;
    ListNode last;
    int usedSize;

    public void offer(int val) {
        ListNode node = new ListNode(val);
        if (head == null) {
            head = node;
            last = node;
        } else {
            last.next = node;
            last = node;
        }
        usedSize++;
    }

    public int getUsedSize() {
        return usedSize;
    }

    public int poll() {
        if (head == null) {
            return -1;
        }
        int val = head.val;
        if (head == last) {
            head = null;
            last = null;
            return val;
        }
        head = head.next;
        usedSize--;
        return val;
    }
    public int peek() {
        if (head == null) {
            return -1;
        }
        return head.val;
    }
}

循环队列

例题:

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

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

示例:

MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1);  // 返回 true
circularQueue.enQueue(2);  // 返回 true
circularQueue.enQueue(3);  // 返回 true
circularQueue.enQueue(4);  // 返回 false,队列已满
circularQueue.Rear();  // 返回 3
circularQueue.isFull();  // 返回 true
circularQueue.deQueue();  // 返回 true
circularQueue.enQueue(4);  // 返回 true
circularQueue.Rear();  // 返回 4

提示:

  • 所有的值都在 0 至 1000 的范围内;
  • 操作数将在 1 至 1000 的范围内;
  • 请不要使用内置的队列库。

代码如下:

class MyCircularQueue {
    public int[] i;
    public int front;
    public int rear;


    public MyCircularQueue(int k) {
        this.i = new int[k+1];
    }
    
    public boolean enQueue(int value) {
        if(isFull()){
            return false;
        }else{
            i[rear] = value;
            rear = (rear+1)%i.length;
        }
        return true;
    }
    
    public boolean deQueue() {
        if(isEmpty()){
            return false;
        }else{
            front = (front+1)%i.length;
        }
        return true;
    }
    
    public int Front() {
        if(isEmpty()){
            return -1;
        }
        return i[front];

    }
    
    public int Rear() {
        if(isEmpty()){
            return -1;
        }
        int index = (rear == 0)?i.length-1:rear-1;
        return i[index];

    }
    
    public boolean isEmpty() {
        return rear == front;

    }
    
    public boolean isFull() {
        return (rear+1)%i.length == front; 

    }
}

/**
 * Your MyCircularQueue object will be instantiated and called as such:
 * MyCircularQueue obj = new MyCircularQueue(k);
 * boolean param_1 = obj.enQueue(value);
 * boolean param_2 = obj.deQueue();
 * int param_3 = obj.Front();
 * int param_4 = obj.Rear();
 * boolean param_5 = obj.isEmpty();
 * boolean param_6 = obj.isFull();
 */

双端队列 (Deque)

双端队列( deque )是指允许两端都可以进行入队和出队操作的队列, deque “double ended queue” 的简称。 那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。
而在使用时必须创建 LinkedList 的对象。

队列题示例

用队列实现栈

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

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

注意:

  • 你只能使用队列的标准操作 —— 也就是 push to backpeek/pop from frontsize 和 is empty 这些操作。
  • 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

示例:

输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]

解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False

提示:

  • 1 <= x <= 9
  • 最多调用100 次 pushpoptop 和 empty
  • 每次调用 pop 和 top 都保证栈不为空

代码如下:

import java.util.LinkedList;
import java.util.Queue;

public class MyStack {
    public Queue<Integer> que1;
    public Queue<Integer> que2;
    public MyStack(){
        que1 = new LinkedList<>();
        que2 = new LinkedList<>();
    }
    public void push(int x) {
        if(!que1.isEmpty()){
            que1.offer(x);
        }else if(!que2.isEmpty()){
            que2.offer(x);
        }else{
            que1.offer(x);
        }

    }

    public int pop() {
        if (empty()) {
            return -1;
        } else if (!que1.isEmpty()) {
            int a = que1.size();
            for (int i = 0; i < a - 1; i++) {
                int x = que1.poll();
                que2.offer(x);
            }
            return que1.poll();
        } else if (!que2.isEmpty()) {
            int a = que2.size();
            for (int i = 0; i < a - 1; i++) {
                int x = que2.poll();
                que2.offer(x);
            }
            return que2.poll();
        }
        return -1;
    }

    public int top() {
        if (empty()) {
            return -1;
        } else if (!que1.isEmpty()) {
            int a = que1.size();
            int x = -1;
            for (int i = 0; i < a ; i++) {
                 x = que1.poll();
                que2.offer(x);
            }
            return x;
        } else if (!que2.isEmpty()) {
            int a = que2.size();
            int x = -1;
            for (int i = 0; i < a ; i++) {
                x = que2.poll();
                que2.offer(x);
            }
            return x;
        }
        return -1;

    }

    public boolean empty() {
        return que1.isEmpty() && que2.isEmpty();

    }
}

  • 15
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值