数据结构——队列(Java实现)

1.2 队列

  • 队列特性: 先进先出
  • 队列是个有序列表,可以使用数组链表实现

1.2.1 数组模拟队列(无环形)

  • 队列本身就是有序列表,如果使用数组的结构来实现队列,那么队列数组的声明如下图:
    在这里插入图片描述

  • 因为队列的输出、输入是分别从前后端来处理,因此需要两个变量 front 及 rear 分别记录队列前后端的下标, front 会随着数据输出而改变,而 rear 则是随着数据输入而改变,如队列介绍中图所示

  • maxSize是队列的最大容量

  • 入队addQueue()思路分析:

    • 1.入队时,将rear的指针+1,并且注意当队列为的时候font == rear
    • 2.若指针rear小于队列的最大下标maxSize-1时,才能够存入数据,否则的话无法存入数据 。注意当队列为的时候 rear == maxSize -1
  • 注意:font并没有直接指向队列数据的第一位,而是指向队列头的前一位,所以需要读取队列头的时候需要使用font+1

  • 注意:本队列的缺点,没有实现环形队列,出队的数据其实还是在队列数组内,只是指向队列头的指针变化了

实现代码

import java.util.List;
import java.util.Scanner;

class MyQueue{
    private int maxSize;// 队列最大容量
    private int font;// 队列头指针
    private int rear;// 队列尾指针
    private int[] arrayQueue;// 队列数组
    public MyQueue(int maxSize){ // 初始化队列
        this.maxSize = maxSize;
        font = -1;
        rear = -1;
        arrayQueue = new int[maxSize];
    }
    public boolean isEmpty(){ // 判断队列是否为空
        return font == rear;
    }
    public boolean isFull(){ // 判断队列是否满了
        return rear == maxSize-1;
    }
    public void addQueue(int a){
        if(!isFull()){
            rear++;
            arrayQueue[rear] = a;
        }else
            System.out.println("队列满了!");
    }
    public int popQueue() {
        if (!isEmpty()) {
            font++;
            return arrayQueue[font];
        } else {
            System.out.println("队列为空!");
            return -1;
        }
    }
    public int getHead(){
        if (!isEmpty()){
            return arrayQueue[font+1];
        }else {
            throw new RuntimeException("队列为空");
        }
    }
    public void showQueue(){
        if (!isEmpty()){
            int count = 0;
            for(int i=font+1;i<rear+1;i++){
                System.out.println("Queue["+count+"]: "+arrayQueue[i]);
                count++;
            }
        }else
            System.out.println("队列为空!");
    }
}
public class ArrayQueueDemo01 {
    public static void main(String[] args) {
        System.out.print("请输入队列的最大容量:");
        Scanner scanner = new Scanner(System.in);
        int maxSize = scanner.nextInt();
        MyQueue myQueue = new MyQueue(maxSize);
        boolean isOk = true;
        while (isOk){
            System.out.println("s(show):显示全部队列");
            System.out.println("a(add):入队");
            System.out.println("p(pop):出队");
            System.out.println("h(getHead):获取队列头");
            System.out.println("e(exit):退出");
            System.out.print("请输入命令: ");
            char key = scanner.next().charAt(0);
            switch (key){
                case 's': {
                    myQueue.showQueue();
                    break;
                }
                case 'a': {
                    System.out.print("请输入添加数据: ");
                    int add = scanner.nextInt();
                    myQueue.addQueue(add);
                    System.out.println("入队: "+add);
                    break;
                }
                case 'p': {
                    System.out.println("出队: "+myQueue.popQueue());
                    break;
                }
                case 'h': {
                    System.out.println("队列头: "+myQueue.getHead());
                    break;
                }
                case 'e': {
                    System.out.println("退出");
                    isOk = false;
                    break;
                }
                default:
                    System.out.println("输入错误!");
            }
        }
    }
}

1.2.2 环形数组模拟队列

优化

  • font指针的初始值为0,font直接指向队列的第一个数据,判断队列为的条件为rear == font

  • rear指向队列的最后一个数据的后面一个位置,所以rear指针的初始值为0(前一位是-1),即

    arrayQueue[rear-1] = 最后一个数据

  • 队列的条件是:(rear +1) % maxSize = font

  • 为了区分队满和队空,所以需要浪费一个空间作为指针的停靠,因此才造成了队满条件为**(rear+1)% maxSize = font**,

    • 为什么需要+1:因为这个时候实际上rear指针在font指针前一个位置(浪费的空间内)
    • 为什么需要%maxSize:避免出现数组下标越界的问题
  • 所以整个队列内有效数据的个数为:((rear-1)-font+1)% maxSize,即**(rear-font+maxSize)% maxSize**

    • 为什么需要添加maxSize?

    • 因为队列是个循环队列,那么rear和font的下标值是一直处于变化的,所以会出现rear小于font的情况,这个时候只需要加上一个maxSize就可以将rear-font的值从负转为正,可以看下图帮助理解:
      在这里插入图片描述

  • 入队时rear : rear = (rear+1) % maxSize

  • 出队时font : font = (font+1) % maxSize

  • 如图:

    • maxSize = 8,rear = 8, font = 1
    • (rear+1) % maxSize = 1 = font 队满
      在这里插入图片描述
      一篇讲的很好的博客 通俗易懂讲解循环队列原理_派大星⭐的博客-CSDN博客(https://blog.csdn.net/qq_44280408/article/details/104017937)

实现代码

import java.util.Scanner;

class circleQueue{
    private int maxSize;// 队列最大容量
    private int font;// 队列头指针
    private int rear;// 队列尾指针
    private int[] arrayQueue;// 队列数组
    public circleQueue(int maxSize){ // 初始化队列
        this.maxSize = maxSize+1;
        font = 0;
        rear = 0;
        arrayQueue = new int[this.maxSize];
    }
    public boolean isEmpty(){ // 判断队列是否为空
        return font == rear;
    }
    public boolean isFull(){ // 判断队列是否满了
        return (rear+1)%maxSize == font;
    }
    public void addQueue(int a){ // 入队
        if(!isFull()){
            arrayQueue[rear%maxSize] = a;
            rear = (rear+1) % maxSize;
        }else
            System.out.println("队列满了!");
    }
    public int popQueue() { // 出队
        if (!isEmpty()) {
            int temp = arrayQueue[font];
            font = (font+1) % maxSize;
            return temp;
        } else {
            System.out.println("队列为空!");
            return -1;
        }
    }
    public int getHead(){
        if (!isEmpty()){
            return arrayQueue[font];
        }else {
            throw new RuntimeException("队列为空");
        }
    }
    public void showQueue(){
        if (!isEmpty()){
            int count = 0;
            for(int i=font;i<font+getNums();i++){
                // 注意要防止下标越界
                System.out.println("Queue["+count+"]: "+arrayQueue[i%maxSize]);
                count++;
            }
        }else
            System.out.println("队列为空!");
    }
    public int getNums(){ // 获取当前队列内有效数据的个数
        return (rear - font + maxSize) % maxSize;
    }
}
public class ArrayQueryDemo02 {
    public static void main(String[] args) {
        System.out.print("请输入队列的最大容量:");
        Scanner scanner = new Scanner(System.in);
        int maxSize = scanner.nextInt();
        circleQueue circleQueue = new circleQueue(maxSize);
        boolean isOk = true;
        while (isOk){
            System.out.println("s(show):显示全部队列");
            System.out.println("a(add):入队");
            System.out.println("p(pop):出队");
            System.out.println("h(getHead):获取队列头");
            System.out.println("e(exit):退出");
            System.out.print("请输入命令: ");
            char key = scanner.next().charAt(0);
            switch (key){
                case 's': {
                    circleQueue.showQueue();
                    break;
                }
                case 'a': {
                    System.out.print("请输入添加数据: ");
                    int add = scanner.nextInt();
                    circleQueue.addQueue(add);
                    System.out.println("入队: "+add);
                    break;
                }
                case 'p': {
                    System.out.println("出队: "+circleQueue.popQueue());
                    break;
                }
                case 'h': {
                    System.out.println("队列头: "+circleQueue.getHead());
                    break;
                }
                case 'e': {
                    System.out.println("退出");
                    isOk = false;
                    break;
                }
                default:
                    System.out.println("输入错误!");
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
算法与数据结构它们分别涵盖了以下主要内容: 数据结构(Data Structures): 逻辑结构:描述数据元素之间的逻辑关系,如线性结构(如数组、链表)、树形结构(如二叉树、堆、B树)、图结构(有向图、无向图等)以及集合和队列等抽象数据类型。 存储结构(物理结构):描述数据在计算机中如何具体存储。例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并分析这些操作的时间复杂度和空间复杂度。 算法: 算法设计:研究如何将解决问题的步骤形式化为一系列指令,使得计算机可以执行以求解问题。 算法特性:包括输入、输出、有穷性、确定性和可行性。即一个有效的算法必须能在有限步骤内结束,并且对于给定的输入产生唯一的确定输出。 算法分类:排序算法(如冒泡排序、快速排序、归并排序),查找算法(如顺序查找、二分查找、哈希查找),图论算法(如Dijkstra最短路径算法、Floyd-Warshall算法、Prim最小生成树算法),动态规划,贪心算法,回溯法,分支限界法等。 算法分析:通过数学方法分析算法的时间复杂度(运行时间随数据规模增长的速度)和空间复杂度(所需内存大小)来评估其效率。 学习算法与数据结构不仅有助于理解程序的内部工作原理,更能帮助开发人员编写出高效、稳定和易于维护的软件系统。
逻辑结构:描述数据元素之间的逻辑关系,如线性结构(如数组、链表)、树形结构(如二叉树、堆、B树)、图结构(有向图、无向图等)以及集合和队列等抽象数据类型。 存储结构(物理结构):描述数据在计算机中如何具体存储。例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并分析这些操作的时间复杂度和空间复杂度。 算法: 算法设计:研究如何将解决问题的步骤形式化为一系列指令,使得计算机可以执行以求解问题。 算法特性:包括输入、输出、有穷性、确定性和可行性。即一个有效的算法必须能在有限步骤内结束,并且对于给定的输入产生唯一的确定输出。 算法分类:排序算法(如冒泡排序、快速排序、归并排序),查找算法(如顺序查找、二分查找、哈希查找),图论算法(如Dijkstra最短路径算法、Floyd-Warshall算法、Prim最小生成树算法),动态规划,贪心算法,回溯法,分支限界法等。 算法分析:通过数学方法分析算法的时间复杂度(运行时间随数据规模增长的速度)和空间复杂度(所需内存大小)来评估其效率。 学习算法与数据结构不仅有助于理解程序的内部工作原理,更能帮助开发人员编写出高效、稳定和易于维护的软件系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值