用Java实现简单的队列数据结构

简介: 用Java实现简单的队列数据结构

这篇文章我们再来介绍一个基本的数据结构:队列

使用场景:

要认识一个数据结构,先来认识一下这个数据结构的应用场景:队列主要是用于排队等场景,像是在买东西排队时,如下图


队列介绍:

认识了队列,我们看一下队列在实现时需要遵循什么原则:

1.队列是一个有序列表,可以用数组或链表来实现(本文我们先用数组来实现,后面我们再介绍链表的代码实现)

2.遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出

3.示意图:

(我们先来介绍简易的队列,后面介绍高级一点的循环队列

代码实现:

下面我们来介绍一下这个数据结构用数组实现的思路分析以及代码实现

队列本本身是有序的,如果用数组模拟,则遵循上图的演示。
maxSize是队列的最大空间,front指向数组的第一个元素的前一个位置,rear指向第一个元素,front会随着数据的输出而改变,rear会随着数据的增加而改变

下面我们边写代码边分析

package java.arrayqueu;
import java.util.Scanner;
/**
 * 使用数组模拟队列,此程序不是循环队列
 * @author ZhuQiPeng
 * 
 * 1.先编写Queue类,其中的属性等要体现封装性
 * 2.用构造器初始化队列,此队列的front和rear初始化为-1
 * 3.其中的方法包括isFull、isEmpty、addQueue、getQueue、showQueue、headQueue
 * 
 * 然后编写main函数
 * main函数中写测试
 * 提供用户界面
 * 创建一个字符用于接受用户输入
 * 通过用户的选择调用Queue类中的方法
 */
public class ArrayQueue {
  public static void main(String[] args) {
    //main函数里面写测试
    //创建一个队列
    Queue queue = new Queue(3);
    char key = ' ';
    Scanner scanner = new Scanner(System.in);
    boolean loop = true;
    //输出一个菜单
    while(loop) {
      System.out.println("s(show): 显示队列");
      System.out.println("e(exit): 退出程序");
      System.out.println("a(add): 添加数据到队列");
      System.out.println("g(get): 从队列取出数据");
      System.out.println("h(head): 查看队列头的数据");
      key = scanner.next().charAt(0);//接受一个字符
      switch(key) {
      case 's':
        queue.showQueue();
        break;
      case 'a':
        System.out.println("输入一个数");
        int value = scanner.nextInt();
        queue.addQueue(value);
        break;
      case 'g':
        try {
          int res = queue.getQueue();
          System.out.printf("取出的数据是%d\n",res);
        }
        catch(Exception e) {
          System.out.println(e.getMessage());
        }
        break;
      case 'h':
        try {
          int res = queue.headQueue();
          System.out.printf("队列的头数据为%d\n",res);
        }catch(Exception e) {
          System.out.println(e.getMessage());
        }
        break;
      case 'e':
        scanner.close();
        loop = false;
        break;
      default:
        break;
      } 
    }
    System.out.println("程序退出~~");
  }
}
class Queue{
  private int maxSize;//数组的最大容量
  private int front;//头部
  private int rear;//尾部
  private int[] arr;//该数据用于存放数据, 模拟队列
  //用构造器初始化队列
  public Queue(int maxSize) {
    this.maxSize = maxSize;
    arr = new int[maxSize];
    front = -1;
    rear = -1;
  }
  //判断队列是否满
  public boolean isFull() {
    return rear == maxSize - 1;
  }
  //判断队列是否满
  public boolean isEmpty() {
    return rear == front;
  }
  //添加数据到队列
  public void addQueue(int n) {
    //先判断队列是否满
    //如果队列满则提示信息并退出方法
    if(isFull()) {
      System.out.println("队列已满,不能加入数据");
      return;
    }
    //因为front指向的是头元素的前一个位置
    arr[++rear] = n;//先让rear后移再添加
  }
  //获取元素(出队)
  public int getQueue() {
    //先判断队列是否为空
    if(isEmpty()) {//如果队列为空
      //通过抛出异常结束程序
      throw new RuntimeException("队列为空,不能取数据");
    }
    return arr[++front];//先后移front,理由同上
  }
  //显示队列所有元素
  public void showQueue() {
    //遍历
    //如果队列满则提示信息并退出方法
    if(isEmpty()) {
      System.out.println("队列为空,没有数据!");
      return;
    }
    for(int i = front+1;i<arr.length;i++) {
      System.out.printf("arr[%d]=%d\n",i,arr[i]);
    }
  }
  //显示队列头元素,注意不是取数据
  public int headQueue() {
    //如果是空没法显示
    if(isEmpty()) {
      throw new RuntimeException("队列为空,没有数据!");
    }
    return arr[front+1];//由于不是取数据,所以front不需要++
  }
}

问题分析并优化:

1.目前数组只能使用一次,达到长度后没法复用

2.改进成为一个环形队列

由于该数组可反复取放元素,所以需要用到取模(%)运算,将数组下标运算到相应的位置,具体的改变见代码分析。

思路分析:

当我们用一般队列时,判断队列是否满的条件是rear=front,现在,因为不知道rear和front的相对位置,所以需要取模。
由于是环形队列,所以rear会一直增加,但是最大只能是maxSize-1,为了不超过这个值,需要取模获得rear的真实位置。

代码实现:

package Java.arrayqueu;
import java.util.Scanner;
/**
 * 用数组模拟的循环队列
 * @author ZhuQiPeng
 * 
 * 与普通队列的不同点:
 * 1.front和rear从0开始,front指向队列的第一个元素,rear指向最后一个元素
 * 2.front和rear后移时,要考虑取模
 * 3.遍历时要计算长度
 * 4.rear后面留出一个
 * 5.增加了一个方法,用来计算队列的长度,为遍历时用
 * 
 * 后移以及计算长度时的公式
 * 1.判断是否满:(rear + 1)%maxSize == front,当rear<maxSize-1时,取模后,仍然为rear本身,
 * 当超过时,取模后,rear又回到了0~maxSize-1,然后与front相比,确定是否重合,从而确定是否满
 * 2.判断是否为空时,仍然为rear==front;
 * 3.front 和 rear 自增时,判断下一个位置,(front+1)%maxSize或(rear+1)%maxSize
 * 
 * 
 */
public class CircleArrayQueue {
  public static void main(String[] args) {
    //创建一个环形队列
    CircleQueue queue = new CircleQueue(4);//由于预留一个位置,有效元素是3
    char key = ' '; // 接收用户输入
    Scanner scanner = new Scanner(System.in);
    boolean loop = true;
    // 输出一个菜单
    while(loop) {
      System.out.println("s(show): 显示队列");
      System.out.println("e(exit): 退出程序");
      System.out.println("a(add): 添加数据到队列");
      System.out.println("g(get): 从队列取出数据");
      System.out.println("h(head): 查看队列头的数据");
      key = scanner.next().charAt(0);// 接收一个字符
      switch(key) {
      case 's':
        queue.showQueue();
        break;
      case 'a':
        System.out.println("输入一个数");
        int value = scanner.nextInt();
        queue.addQueue(value);
        break;
      case 'g': 
        try {
          int res = queue.getQueue();
          System.out.printf("取出的数据是%d\n", res);
        } catch (Exception e) {
          System.out.println(e.getMessage());
        }
        break;
      case 'h': 
        try {
          int res = queue.headQueue();
          System.out.printf("队列头的数据是%d\n", res);
        } catch (Exception e) {
          System.out.println(e.getMessage());
        }
        break;
      case 'e': 
        scanner.close();
        loop = false;
        break;
      default:
        break;
      }
    }
    System.out.println("程序退出~~~");
  }
}
class CircleQueue{
  private int maxSize;//数组的最大容量
  //front变量做一个调整: front就指向队列的第一个元素,也就是说arr[front]就是队列的第一个元素
  //front的初始值为0
  private int front;//头部
  //rear 的初始值为0
  private int rear;//队列尾
  private int[] arr;//该数据用于存放数据, 模拟队列
  public CircleQueue(int maxSize) {
    this.maxSize = maxSize;
    arr = new int[maxSize];
    //int型变量默认初始化为0,所以这里可以不写
  }
  // 判断队列是否满
  public boolean isFull(){
    return (rear + 1) % maxSize == front;   
  }
  //判断队列是否空
  public boolean isEmpty() {
    return rear == front;
  }
  //添加数据到队列
  public void addQueue(int index) {
    // 判断队列是否满
    if (isFull()) {
      System.out.println("队列满,不能加入数据~");
      return;
    }
    //直接将数据加入
    arr[rear] = index;
    //rear后移,要考虑取模
    rear = (rear + 1) % maxSize;
  }
  //获取队列的数据,出队列
  public int getQueue() {
    //判断队列是否空
    if(isEmpty()) {
      throw new RuntimeException("队列空,不能取数据");
    }
    //出队,front后移,需要考虑取模
    //先把front保存到临时变量
    //front后移(考虑取模)
    //将临时变量的值返回
    int val = arr[front];
    front = (front+1) % maxSize;
    return val;   
  }
  //显示队列所有元素
  public void showQueue() {
    //先判断是否为空
    if(isEmpty()) {
      System.out.println("队列为空!");
      return;
    }
    //由于是循环队列,所以遍历时需要考虑取模
    //由于不知道front和rear的相对位置,所以需要计算遍历多少个元素
    for(int i = front;i < front + size(); i++) {
      System.out.printf("arr[%d]=%d\n",i % maxSize,arr[i % maxSize]);
    }
  }
  //求出当前队列的有效数据的个数
  private int size() {
    return (rear + maxSize - front)%maxSize;
  }
  // 显示队列的头数据, 注意不是取出数据
  public int headQueue() {
    // 判断
    if (isEmpty()) {
      throw new RuntimeException("队列空的,没有数据~~");
    }
    return arr[front];
  }
}

思路分析在代码里面有了~大家有什么疑问尽管问,我尽量为大家作答

关于队列,这篇文章就到这里了,后面我还会写关于面向对象的文章~

往期推荐:

一篇文章搞定Java稀疏数组!

相关文章
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
159 9
|
2月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
91 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
2月前
|
存储 Java
Java中的HashMap和TreeMap,通过具体示例展示了它们在处理复杂数据结构问题时的应用。
【10月更文挑战第19天】本文详细介绍了Java中的HashMap和TreeMap,通过具体示例展示了它们在处理复杂数据结构问题时的应用。HashMap以其高效的插入、查找和删除操作著称,而TreeMap则擅长于保持元素的自然排序或自定义排序,两者各具优势,适用于不同的开发场景。
47 1
|
2月前
|
存储 Java
告别混乱!用Java Map优雅管理你的数据结构
【10月更文挑战第17天】在软件开发中,随着项目复杂度增加,数据结构的组织和管理至关重要。Java中的Map接口提供了一种优雅的解决方案,帮助我们高效、清晰地管理数据。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,有效提升了代码质量和维护性。
93 2
|
2月前
|
存储 Java 开发者
Java Map实战:用HashMap和TreeMap轻松解决复杂数据结构问题!
【10月更文挑战第17天】本文深入探讨了Java中HashMap和TreeMap两种Map类型的特性和应用场景。HashMap基于哈希表实现,支持高效的数据操作且允许键值为null;TreeMap基于红黑树实现,支持自然排序或自定义排序,确保元素有序。文章通过具体示例展示了两者的实战应用,帮助开发者根据实际需求选择合适的数据结构,提高开发效率。
71 2
|
3天前
|
存储 缓存 安全
Java 集合江湖:底层数据结构的大揭秘!
小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
21 5
|
17天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
38 5
|
1月前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
47 6
|
1月前
|
存储 Java 索引
Java中的数据结构:ArrayList和LinkedList的比较
【10月更文挑战第28天】在Java编程世界中,数据结构是构建复杂程序的基石。本文将深入探讨两种常用的数据结构:ArrayList和LinkedList,通过直观的比喻和实例分析,揭示它们各自的优势与局限,帮助你在面对不同的编程挑战时做出明智的选择。
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!