[数据结构] 队列 (Queue)

1.概念

队列 : 只允许在一段进行插入数据操操作 , 在另一端进行删除数据操作的特殊线性表 ; 队列 先进先出

入队列 : 进行插入操作的一端称为队尾

出队列 : 进行删除操作的一端称为对头

2.队列的使用

在Java中 , Queue 是一个接口 , 底层通过链表实现的

|--------------|-------------------------------------------|----------------|
| 方法 | 行为 | 说明 |
| add(E e) | 添加元素到队尾(若队列已满,抛出 IllegalStateException) | 推荐使用 offer() |
| offer(E e) | 添加元素到队尾(队列满时返回 false) | 更安全的插入方式 |
| remove() | 移除并返回队头元素(队列空时抛出NoSuchElementException) | 推荐使用 poll() |
| poll() | 移除并返回队头元素(队列空时返回 null) | 安全的移除方式 |
| element() | 查看队头元素(不删除,队列空时抛出异常) | 推荐使用 peek() |
| peek() | 查看队头元素(不删除,队列空时返回 null) | 安全的查看方式 |

java 复制代码
public static void main(String[] args) {
    Queue<Integer> queue = new LinkedList<>();
    queue.offer(11);//添加元素到队尾
    queue.offer(12);
    queue.offer(13);
    queue.offer(14);
    queue.offer(15);
    System.out.println(queue);//打印队列  [11, 12, 13, 14, 15]

    int a1 = queue.poll();//移除头元素,并返回
    System.out.println(a1);//11
    System.out.println(queue);//[12, 13, 14, 15]
    int a2 = queue.peek();//获取队头元素
    System.out.println(a2);//12
}

3.队列的模拟实现

①实现队列

java 复制代码
public class MyQueue {
    public static class ListNode{
        public int val;
        public ListNode prev;
        public ListNode next;
        public ListNode(int val){
            this.val = val;
        }
    }
    public int usedSize = 0;
    public ListNode head = null;
    public ListNode last = null;

    public boolean isEmpty(){//检查是否为空
        return usedSize == 0;//如果是空的 , usedSize为0 返回true
    }

    public void offer(int val){//入队列,采用的是尾插法
        ListNode node = new ListNode(val);
        if(isEmpty()){
            head = last =  node;//把node节点赋值给head和last
            usedSize++;
        }else {
            last.next = node;
            node.prev = last;
            last = node;
            usedSize++;
        }
    }
    public int poll(){//相应的出队列应该采用,头删法
        if(isEmpty()) {
            return -1;
        }
        int vall = head.val;
        head = head.next;
        if(head != null){
            head.prev = null;
        }
        usedSize--;
        return vall;
    }
    public int size(){//返回大小
        return usedSize;
    }

}

②测试

java 复制代码
public static void main(String[] args) {
    MyQueue myQueue = new MyQueue();
    myQueue.offer(11);//添加元素到队尾
    myQueue.offer(12);
    myQueue.offer(13);
    myQueue.offer(14);
    myQueue.offer(15);
    System.out.println(myQueue.poll());
}

4.循环队列

  • 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为"环形缓冲器"
  • 循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间
  • 但是使用循环队列,我们能使用这些空间去存储新的值

|--------------------|---------------------|------------------|------------------------------------|-------------------------------|
| 方法名 | 描述 | 参数 | 返回值 | 特殊说明 |
| MyCircularQueue(k) | 构造器,初始化队列,设置队列容量为 k | int k(队列容量) | 无 | 内部实际使用 k+1 的空间来区分空满状态 |
| Front() | 获取队首元素 | 无 | int(队首元素值) | 队列为空时返回 - 1 |
| Rear() | 获取队尾元素 | 无 | int(队尾元素值) | 队列为空时返回 - 1 |
| enQueue(value) | 向队列插入元素 | int value(待插入元素) | boolean(插入成功返回 true,队列满则返回 false) | 插入后队尾指针循环后移 |
| deQueue() | 从队列删除队首元素 | 无 | boolean(删除成功返回 true,队列为空则返回 false) | 删除后队首指针循环后移 |
| isEmpty() | 检查队列是否为空 | 无 | boolean(为空返回 true,否则返回 false) | 当 front == rear 时队列空 |
| isFull() | 检查队列是否已满 | 无 | boolean(已满返回 true,否则返回 false) | 当 (rear+1) % 容量 == front 时队列满 |

java 复制代码
class MyCircularQueue {

    public int front;

    public int rear;

    public int[] elem;



    public MyCircularQueue(int k) {

        elem = new int[k+1];

    }



    //入队列 

    public boolean enQueue(int value) {

        if(isFull()) {

            return false;

        }

        elem[rear] = value;

        rear = (rear+1)%elem.length;

        return true;

    }

    //出队列 

    public boolean deQueue() {

        if(isEmpty()) {

            return false;

        }

        front = (front+1)%elem.length;

        return true;

    }

    //得到队头元素 

    public int Front() {

        if(isEmpty()) {

            return -1;

        }

        return elem[front];

    }



    public int Rear() {

        if(isEmpty()) {

            return -1;

        }

        int index = (rear == 0) ? elem.length-1 : rear-1;

        return elem[index];

    }



    public boolean isEmpty() {

        return rear == front;

    }



    public boolean isFull() {

        return (rear+1)%elem.length == front;

    }

}

5.双端队列(Deque)

双端队列 是 指允许两端都可以进行入队和出队操作的队列

Deque是一个接口, 使用时 必须创建LinkedList对象

Deque的接口比较多 , 栈和队列均可以实现该接口

java 复制代码
public static void main(String[] args) {
    Deque<Integer> stack = new LinkedList<>();//双端队列的链式实现
    Deque<Integer> queue = new ArrayDeque<>();//双端队列的线性实现
}

6.用队列实现栈

  1. 模拟的入栈操作 : 将元素放到不为空的队列中
  2. 模拟的出栈操作 : 把不为空的队列中的size-1个元素放到另一个队列中 ; 最后剩下的就是模拟栈中的顶层元素
java 复制代码
import java.util.LinkedList;
import java.util.Queue;

class MyStackUseQueue {

    public Queue<Integer> qu1;
    public Queue<Integer> qu2;

    public MyStackUseQueue() {
        qu1 = new LinkedList<>();
        qu2 = new LinkedList<>();
    }
    
    public void push(int x) {
        if(!qu1.isEmpty()) {
            qu1.offer(x);
        }else if(!qu2.isEmpty()) {
            qu2.offer(x);
        }else {
            qu1.offer(x);
        }
    }
    
    public int pop() {
        if(empty()) {
            return -1;
        }
        if(!qu1.isEmpty()) {
            int size = qu1.size();
            for(int i = 0;i < size-1;i++) {
                qu2.offer( qu1.poll());
            }
            return qu1.poll();
        }else  {
            int size = qu2.size();
            for(int i = 0;i < size-1;i++) {
                qu1.offer( qu2.poll());
            }
            return qu2.poll();
        }
    }
    
    public int top() {
        if(empty()) {
            return -1;
        }
        if(!qu1.isEmpty()) {
            int size = qu1.size();
            int val = 0;
            for(int i = 0;i < size;i++) {
                val = qu1.poll();
                qu2.offer(val);
            }
            return val;
        }else  {
            int size = qu2.size();
             int val = 0;
            for(int i = 0;i < size;i++) {
                val = qu2.poll();
                qu1.offer(val);
            }
            return val;
        }
    }
    
    public boolean empty() {
        return qu1.isEmpty() && qu2.isEmpty();
    }
}

7.用栈实现队列

  1. 模拟入队操作 : 放到第一个栈中
  2. 模拟出队操作 : 判断第二个栈是否为空 ?

如果为空 : 需要把第一个栈中的所有元素都放到第二个栈里 , 取出第二个栈中的顶层元素

如果不为空 : 直接取出第二个栈中的顶层元素

java 复制代码
import java.util.ArrayDeque;



class MyQueueUseStack {

    public ArrayDeque<Integer> stack1;
    public ArrayDeque<Integer> stack2;

    public MyQueueUseStack() {
        stack1 = new  ArrayDeque<>();
        stack2 = new  ArrayDeque<>();

    }



    public void push(int x) {

        stack1.push(x);

    }



    public int pop() {

        if(empty()) {
            return -1;
        }

        if(stack2.isEmpty()) {
            //第一个栈里面所有的元素 放到第二个栈当中 
            while(!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }



    public int peek() {

        if(empty()) {
            return -1;
        }

        if(stack2.isEmpty()) {
            //第一个栈里面所有的元素 放到第二个栈当中 
            while(!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.peek();
    }



    public boolean empty() {
        return stack1.isEmpty() && stack2.isEmpty();
    }
}
相关推荐
自信的小螺丝钉20 小时前
Leetcode 347. 前 K 个高频元素 堆 / 优先队列
算法·leetcode·优先队列·
-雷阵雨-20 小时前
数据结构——优先级队列(堆)
java·开发语言·数据结构·intellij-idea
好家伙VCC20 小时前
**全息显示技术的发散创新与深度探索**一、引言随着科技的飞速发展,全息显示技术已成为显示领域的一大研究热点。本文将带你
java·图像处理·python·科技·计算机视觉
步行cgn20 小时前
Java项目包结构设计与功能划分详解
java·开发语言·架构·mvc
ss27320 小时前
手写MyBatis第92弹:SqlSource体系、SqlNode树与Trim标签实现原理全揭秘
java·开发语言
用手手打人21 小时前
JVM(七)--- 垃圾回收
jvm
2351621 小时前
【LeetCode】46. 全排列
java·数据结构·后端·算法·leetcode·职场和发展·深度优先
_extraordinary_21 小时前
Java Linux --- 基本命令,部署Java web程序到线上访问
java·linux·前端
未知陨落21 小时前
LeetCode:90.最长有效括号
算法·leetcode
zzywxc7871 天前
AI工具应用全解析:智能编码、数据标注与模型训练的协同实践
人工智能·算法·信息可视化·自动化·ai编程