Java数据结构之队列示例详解

 更新时间:2025年12月21日 11:37:08   作者:鸽鸽程序猿  
队列是一种线性数据结构,它遵循先进先出或后近后出的原则,队列允许在一端插入元素,另一端删除元素,这篇文章主要介绍了Java数据结构之队列的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、队列

队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表,一种先进先出的数据结构。

队尾:允许插入的一端。

队头:允许删除的一端。

二、队列的模拟实现

队列的底层可以是顺序表,可以是链表实现。

2.1 队列的链式实现

在实现队列前我们先思考使用什么样的链表来实现?

由于栈的特性是先入先出,如果使用单链表和双向链表都可以,

只要在单链表标记一下尾节点就行,

但是因为Java提供的是双向链表实现的,所以我们使用双向链表。

2.1.1 接口实现

实现的接口如下:

public class MyQueue {
	//入队列
    public void offer(int val) {}
	//出队列
    public int poll() {}
    //获取队头元素 但是不删除
    public int peek() { }
    //判空
    public boolean isEmpty() { } 
    //获取队列元素个数
    public int size(){}      
}

2.1.2 内部类

跟双向链表的内部类实现差不多。

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

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

2.1.3 入队列

实现思路:

  1. 先看队列是否为空,为空,头尾指向入队节点。
  2. 不为空尾节点的后继next指向入队节点,入队节点前驱prev指向尾节点,尾节点变为入队节点。
public void offer(int val){
	ListNode cur = new ListNode(val);
	if(isEmpty()){
		head = last = cur;
		return;
	}
	last.next = newNode;
    newNode.prev = last;
    last = newNode;
}

2.1.4 出队列

实现思路:

  1. 先判断队列是否为空,队列为空抛异常。
  2. 队列不为空,将头节点记录下来,头节点后一个节点前驱prev置为空,头节点变为后一个节点。
public int poll() throws NullPointerException{
	try{
		if(isEmpty()){
			throw new NullPointerException;
		}
	}catch(NullPointerException e){
		 e.printStackTrace();
	}
	ListNode cur = head;
	head.next.prev = null;
	head = head.next;
	return cur.val;
}

2.1.5 获取队头元素 但是不删除

实现思路:

  1. 先判断队列是否为空,队列为空抛异常。
  2. 队列不为空,返回头节点。
 public int peek() throws NullPointerException{
	try{
		if(isEmpty()){
			throw new NullPointerException;
		}
	}catch(NullPointerException e){
		 e.printStackTrace();
	}
	return head.val;
}

2.1.6 判空

直接返回头是否为空就行。

public boolean isEmpty(){
	return head == null;
}

2.1.7 获取队列元素个数

直接循环遍历即可。

    public int size(){
    	ListNode cur = head;
    	int size = 0;
		while(cur != null){
			cur = cur.next;
			size++;
		}
		return size;
	} 

2.2 队列的顺序实现(循环队列)

2.2.1 直接使用顺序表的缺陷

当我们直接使用顺序表来放数据时,我们将元素入队列放在数组尾,出队列时将数组前面元素出去后,会使前面浪费的空间越来越大。

基于此我们就用循环队列来实现,还是数组作为底层,但我们将其想象成一个圆。

2.2.2 接口实现

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

2.2.3 成员变量

数组arr ,头下标front,尾节点下一个下标rear,数组长度size。

private int []arr;
private int front;
private int rear;
private int size;

2.2.4 构造器,设置队列长度为 k

因为我们使用的判空方法(下文讲)会造成一个空间的浪费,所以多申请一个空间。

public MyCircularQueue(int k) {
        size = k+1;
        arr = new int[size];
        front = rear = 0;
    }

2.2.5 向循环队列插入一个元素 成功插入则返回真

实现思路:

  1. 判断队列是否已满,满了就返回false。
  2. 不满就在rear放。
  3. 因为是循环队列,所以rear的赋值要使用取余。
public boolean enQueue(int value) {
        if(isFull()){
            return false;
        }else{
            arr[rear] = value;
            rear = (rear + 1) % size;
            return true;
        }
    }

2.2.6 从循环队列中删除一个元素 成功删除则返回真

实现思路:

  1. 判断队列是否为空,空就返回false。
  2. 不空就直接将front指向下一个位置。
  3. 因为是循环队列,所以front的赋值要使用取余。
public boolean deQueue() {
        if(isEmpty()){
            return false;
        }else{
            front = (front + 1) % size;
            return true;
        }
    }

2.2.7 从队首获取元素。如果队列为空,返回 -1

实现思路:

  1. 先判断队列是否为空,为空返回-1。
  2. 不为空,返回front下标对应值。
public int Front() {
        if(isEmpty()){
            return -1;
        }else{
            return arr[front];
        }
    }

2.2.8 获取队尾元素。如果队列为空,返回 -1

实现思路:

  1. 先判断队列是否为空,为空返回-1。
  2. 不为空,再判断rear是否为0,是0就返回数组最后一个元素。
  3. 不为0,就直接返回rear-1下标对应的元素。
public int Rear() {
         if(isEmpty()){
            return -1;
        }else{
            if(rear == 0){
                return arr[size - 1];
            }else{
                return arr[rear - 1];
            }                    
        }
    }

2.2.9 检查循环队列是否为空

检查空根据循环队列的实现有两种方法:

  1. 使用usedSize记录队列元素个数,个数为0就是空。
  2. 空一个空间,如果front和rear相等那就是空。
public boolean isEmpty() {
        return rear == front;
    }

2.2.10 检查循环队列是否已满

检查满根据循环队列的实现有两种方法:

  1. 使用usedSize记录队列元素个数,个数和size相等就是满。
  2. 空一个空间,如果rear的下一个位置就是front那就是满。
public boolean isFull() {
        return front == (rear+1) % size;
    }

三、Java中的Queue

Java中Queue的底层是LinkedList实现的。

并且Queue只是一个接口,必须new对象LinkedList才能使用。

3.1 实现的接口

实现的接口如下:

3.2 常用方法

常用方法如下:

四、队列练习

用队列实现栈

用栈实现队列

设计循环队列

到此这篇关于Java数据结构之队列示例详解的文章就介绍到这了,更多相关Java数据结构队列内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解Springboot 注入装配到IOC容器方式

    详解Springboot 注入装配到IOC容器方式

    今天通过实例代码给大家介绍了Springboot 注入装配到IOC容器方式,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,感兴趣的朋友跟随小编一起看看吧
    2021-10-10
  • Java中占位符的超全使用方法分享

    Java中占位符的超全使用方法分享

    这篇文章主要为大家详细介绍了Java中常见的一些占位符的使用方法,例如%d,%s等,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习学习
    2023-05-05
  • 关于远程调用RestTemplate的使用避坑指南

    关于远程调用RestTemplate的使用避坑指南

    这篇文章主要介绍了关于远程调用RestTemplate的使用避坑指南,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • 如何使用Resttemplate和Ribbon调用Eureka实现负载均衡

    如何使用Resttemplate和Ribbon调用Eureka实现负载均衡

    这篇文章主要介绍了如何使用Resttemplate和Ribbon调用Eureka实现负载均衡,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Java验证时间格式是否正确方法类项目实战

    Java验证时间格式是否正确方法类项目实战

    在很多场景中我们需要验证时间日期的是否属于正确的格式,验证时间是否符合常规的,本文就来介绍一下几种方式,感兴趣的可以了解一下
    2022-04-04
  • SpringFactoriesLoader类作用详解

    SpringFactoriesLoader类作用详解

    SpringFactoriesLoader可以加载jar包下META-INF下的spring.factories,把相关接口的实现按照key,value的形式加载到内存,一个接口的多个实现可以按照","进行分割
    2022-10-10
  • springboot启动类如何剔除扫描某个包

    springboot启动类如何剔除扫描某个包

    这篇文章主要介绍了springboot启动类如何剔除扫描某个包,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • MyBatis-Plus updateById方法更新不了空字符串/null的问题及解决

    MyBatis-Plus updateById方法更新不了空字符串/null的问题及解决

    MyBatis-Plus的updateById()方法在更新字段为null时会失败,因为默认策略不更新null值,文章提供三种解决方案:全局配置忽略判断、使用PO对象的el属性指定jdbcType、通过注解设置字段验证策略为IGNORED
    2026-03-03
  • JVM 心得分享(加载 链接 初始化)

    JVM 心得分享(加载 链接 初始化)

    下面小编就为大家带来一篇JVM 心得分享(加载 链接 初始化)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • JDK8接口的默认与静态方法-接口与抽象类的区别详解

    JDK8接口的默认与静态方法-接口与抽象类的区别详解

    这篇文章主要介绍了JDK8接口的默认与静态方法-接口与抽象类的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,,需要的朋友可以参考下
    2019-06-06

最新评论