数据结构-Queue队列

一,队列的简单认识

队列也是一种线性数据结构,与栈不同的是,它只能从一端添加元素,从另一端取出元素.定义了一端,另一端也就确定了.

(当然还有一个特殊的双向队列LinkedList除外,它既可以从队首添加元素,也可以移除元素,队尾也是一样的,既可以添加元素,也可以移除元素)

二,队列的实现

Queue<E>

1,void enqueue(E) //添加元素

2,E dequeue() //移除元素

3,E getFront() //获取第一个元素,但不移除

4,int getSize() //获取索引

5,boolean isEmpty() //判断队列是否为空

三,队列代码实现,

了解队列的基本功能,对队列的功能进行代码实现,底层逻辑为数组,同样栈也可以实现队列的功能,队列也可以实现栈的功能.

(注意:利用泛型可以对任意类型的数据进行操作)

1,用抽象类来封装相关功能

复制代码
public interface Queue<T> {
    // 入队的方法
    void enqueue(T ele);

    // 出队的方法
    T dequeue();

    // 查看队首元素
    T getFront();

    // 队列中元素的数量
    int getSize();

    // 判断队列是否为空
    boolean isEmpty();
}

2,用数组来实现队列功能

复制代码
import java.util.Optional;
import java.util.Random;

// 封装属于自己的数组,使用泛型
public class CycleArray<T> {
    private T[] data; // 底层数据结构
    private int size;// 用来保存实际存放元素的个数

    private int capacity; // 表示容积

    // 声明索引
    private int front, tail;

    public CycleArray() {
        this(5);
    }

    public CycleArray(int capacity) {
        this.capacity = capacity;
        this.data = (T[]) new Object[this.capacity + 1];
        this.size = 0;
        this.front = this.tail = 0;
    }

    // 获取容积的方法
    public T getFront() {
        if (this.isEmpty()) {
            return null;
        }
        return this.data[this.front];
    }

    // 判断数组是否为空
    public boolean isEmpty() {
        return this.front == this.tail;
    }

    // 获取数组实际存放元素的个数
    public int getSize() {
        return this.size;
    }

    /**
     * 在尾部添加
     *
     * @param val 插入的值
     */
    public void addTail(T val) {

        // 在增加之前,判断数组是否已满,如果已满,要进行扩容
        if ((this.tail + 1) % this.data.length == this.front % this.data.length) {
            // 扩容操作
            resize(this.capacity * 2);
        }

        this.data[this.tail] = val;
        // 更新tail
        this.tail = (this.tail + 1) % this.data.length;
        System.out.println("入队:this.front=" + this.front + ",this.tail=" + this.tail);
        this.size += 1;
    }

    // 改变容积的方法
    private void resize(int newCapacity) {
        System.out.println("--------resize--------");
        // 2、 创建一个新数组
        T[] newArr = (T[]) new Object[newCapacity + 1];

        // 3、将原来数组的内容转移到新数组
        for (int i = 1; i <= this.size; i++) {
            newArr[i - 1] = this.data[this.front];
            this.front = (this.front + 1) % this.data.length;
        }

        this.front = 0;
        this.tail = this.size;
        System.out.println("扩容完成:this.front=" + this.front + ",this.tail=" + this.tail);
        // 4、将newArr赋值给 this.data
        this.data = newArr;
        // 5、将newCapacity 赋值给this.capacity
        this.capacity = newCapacity;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        int curIndex = this.front;
        while (curIndex != this.tail) {
            sb.append(this.data[curIndex]);
            curIndex = (curIndex + 1) % this.data.length;
        }
        String result = sb.toString();
        return result.substring(0, result.length() - 1);
    }


    // 删除队首元素
    public Optional<T> removeFromHead() {
        // 判断是否为空
        if (this.front == this.tail) {
            Optional.empty();
        }
        Optional<T> result = Optional.of(this.data[this.front]);
        // 更新front
        this.front = (this.front + 1) % this.data.length;
        this.size--;

        System.out.println("出队:this.front=" + this.front + ",this.tail=" + this.tail);

        if (this.size <= this.capacity / 4 && this.capacity / 2 > 1) {
            resize(this.capacity / 2);
        }
        return result;
    }
}

3,对功能进行封装

复制代码
public class CycleQueue<T> implements Queue<T> {

    private CycleArray<T> data;

    public CycleQueue() {
        this.data = new CycleArray<>();
    }

    @Override
    public void enqueue(T ele) {
        this.data.addTail(ele);
    }

    @Override
    public T dequeue() {
        return this.data.removeFromHead().orElse(null);
    }

    @Override
    public T getFront() {
        return this.data.getFront();
    }

    @Override
    public int getSize() {
        return this.data.getSize();
    }

    @Override
    public boolean isEmpty() {
        return this.data.isEmpty();
    }
}

五,队列的复杂度分析

六,队列的优势,及用处

在Java中,队列相比栈和数组的优势:

  1. 先入先出(FIFO)的特性:队列保持元素的顺序,确保先入队的元素先被移出队列,这种特性在很多场景下非常有用;

  2. 动态增长:Java中的队列实现类(如LinkedList等)可以动态增长,不需要事先指定队列的大小,因此更灵活;

  3. 提供了更多的操作:队列通常提供了丰富的操作,如入队、出队、查看队首元素等方法,更符合队列数据结构的特性。

队列可以用于解决诸如排队、调度等问题,包括但不限于:

  1. 任务调度:可以使用队列来实现任务的排队执行,确保按照顺序进行;

  2. 缓冲区:可以用队列来作为缓冲区,平衡生产者和消费者之间的速度差异;

  3. 线程安全:多线程环境下可以利用队列来进行线程安全的数据交换;

  4. BFS算法:在图论中,广度优先搜索算法(BFS)通常使用队列来实现,以便按照层级顺序遍历节点。

相关推荐
带刺的坐椅5 分钟前
Solon MVC 的 @Mapping 用法说明
java·mvc·ioc·solon
飞滕人生TYF6 分钟前
java Arrays 详解
java·python·排序算法
xisai8810 分钟前
2025年开考科目有哪些?
java·开发语言·javascript·算法·kotlin
想花12 分钟前
源码分析Spring Boot (v3.3.0)
java·spring boot·后端
陶然同学22 分钟前
RabbitMQ轻松构建高效可靠的消息队列系统
java·网络·分布式·rabbitmq·mq
yangmc041 小时前
判断子序列
开发语言·数据结构·c++·算法·矩阵·图论
新兴AI民工1 小时前
opencv调用扩展库SIFT算法
opencv·算法·sift·opencv420·xfeature2d库
Water_Sunzhipeng1 小时前
The 3rd Universal CupStage 15: Chengdu, November 2-3, 2024(2024ICPC 成都)
算法
席万里1 小时前
C++图案例大全
数据结构·c++·算法
李小白661 小时前
二叉树的练习题(中)
java·数据结构·算法