【Java数据结构与算法】day4-稀疏数组和队列(环形队列)

news2024/12/25 1:44:49

✅作者简介:热爱Java后端开发的一名学习者,大家可以跟我一起讨论各种问题喔。
🍎个人主页:Hhzzy99
🍊个人信条:坚持就是胜利!
💞当前专栏:Java数据结构与算法
🥭本文内容:稀疏数组和数组实现队列和环形队列


文章目录

  • 稀疏数组
  • 队列
  • 环形队列
  • 结语


稀疏数组

基本介绍
当一个数组大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。
稀疏数组的处理方法:

  1. 记录数组一 共有几行几列,有多少个不同的值
  2. 把具有不同值的元素的行列及值记录在一个小规模的数组中,从而 缩小程序 的规模。

二维数组转稀疏数组的思路
1.遍历原始的二维数组,得到有效数据的个数sum
2.根据sum就可以创建稀疏数组sparseArr int[sum+ 1][3]
3.将二维数组的有效数据存入到稀疏数组
稀疏数组转原始的二维数组思路
1.先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组
2.再读取稀疏数组后几行的数据,并赋给原始的二维数组即可。
代码实现

public class Sparsearray {
    public static void main(String[] args) {
        //创建一个原始的二维数组11*11
        //0:表示没有棋子, 1表示 黑子 2 表示 蓝子
        int chessArr1[][] = new int[11][11];
        chessArr1[1][2] = 1;
        chessArr1[2][3] = 2;
        chessArr1[4][5] = 2;
        //输出原始的二维数组
        System.out.println("原始的二维数组");
        for (int[] row :
                chessArr1) {
            for (int data:
                 row) {
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }

        //将二维数组转换成稀疏数组
        //1.先遍历二维数组 得到非零的值
        int sum = 0;
        for (int[] row :
                chessArr1) {
            for (int data:
                    row) {
                if(data != 0)
                    sum++;
            }
        }
        //2.创建对应的稀疏数组
        int sparseArr[][] = new int[sum+1][3];
        //给稀疏数组赋值
        sparseArr[0][0] = chessArr1.length;
        sparseArr[0][1] = chessArr1[0].length;
        sparseArr[0][2] = sum;

        //3.遍历二维数组,将非零的值存放到稀疏数组中
        int count = 0;//用于记录第几个非零数据
        for (int i = 0; i < chessArr1.length; i++) {
            for (int j = 0; j < chessArr1[0].length; j++) {
                if(chessArr1[i][j] != 0){
                    count++;
                    sparseArr[count][0] = i;
                    sparseArr[count][1] = j;
                    sparseArr[count][2] = chessArr1[i][j];
                }
            }
        }

        //输出稀疏数组的值
        System.out.println();
        System.out.println("得到的稀疏数组如下形式~~~~");
        for (int i = 0; i < sparseArr.length; i++) {
            System.out.printf("%d\t%d\t%d\n",sparseArr[i][0],sparseArr[i][1],sparseArr[i][2]);
        }

        //将稀疏数组恢复成原始数组
        int chessArr2[][] = new int[sparseArr[0][0]][sparseArr[0][1]];

        //读取稀疏数组后几行的数据,赋值给原始数组
        for (int i = 1; i < sparseArr.length; i++) {
                chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }

        //恢复后的二维数组
        System.out.println();
        System.out.println("恢复后的二维数组");
        for (int[] row :
                chessArr2) {
            for (int data:
                    row) {
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }

    }
}

队列

队列介绍

  • 队列是一个有序列表 ,可以用数组或者链表来实现
  • 遵循先入先出的原则。
  • 示意图:(数组实现)
    在这里插入图片描述
  • 队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图,其中 maxSize 是该队列的最大容量。
  • 因为队列的输出、输入是分别从前后端来处理,因此需要两个变量front 及 rear分别记录队列前后端的下标,front会随着数据输出而改变,而rear 则是随着数据输入而改变,如图所示:
    在这里插入图片描述
  • 当我们将数据存入队列时称为addQueue, addQueue 的处理需要有两个步骤:
    1)将尾指针往后移: rear+1,当front == rear【空】
    2)若尾指针rear小于队列的最大下标 maxSize-1,则将数据存入rear所指的数组元素中,否则无法存入数据。rear==maxSize-1[队列满]
    代码实现:
public class ArrayQueue {
    public static void main(String[] args) {
        //测试,创建一个队列
        ArrayQueue1 arrayQueue1 = new ArrayQueue1(3);
        char key = ' ';//接受用户输入
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        //输出一个菜单
        while (loop){
            System.out.println("s(show):显示队列");
            System.out.println("e(show):退出程序");
            System.out.println("a(show):添加数据");
            System.out.println("g(show):从队列取出数据");
            System.out.println("h(head):查看队列头数据");
            key = scanner.next().charAt(0);//接受一个字符
            switch(key){
                case 's'://显示数据
                    arrayQueue1.showQueue();
                    break;
                case 'a'://添加数据
                    System.out.println("请输入一个数");
                    int value = scanner.nextInt();
                    arrayQueue1.addQueue(value);
                    break;
                case 'g'://取出数据
                    try {
                        int res = arrayQueue1.getQueue();
                        System.out.printf("取出的数据是%d\n",res);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h'://查看队列头的数据
                    try{
                        int res = arrayQueue1.headQueue();
                        System.out.printf("队列头的数据是%d\n",res);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e'://退出
                    scanner.close();
                    loop = false;
                    break;
            }
        }
        System.out.println("程序退出");
    }
}

//使用数组模拟队列-编写一个ArrayQueue类
class ArrayQueue1{
    private int maxsize;//表示数组最大容量
    private int front;//队列头
    private int rear;//队列尾
    private int[] arr;//该数据用于存放数据,模拟队列

    //创建队列的构造器
    public ArrayQueue1(int arrMaxSize){
        maxsize = arrMaxSize;
        arr = new int[maxsize];
        front = -1;//指向队列头部,分析出front指向队列头的前一个位置
        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;
        }
        rear++;//让rear后移
        arr[rear] = n;
    }

    //获取队列的数据,出队列
    public int getQueue(){
        //判断队列是否空
        if(isEmpty()){
            //通过抛出异常
            throw new RuntimeException("队列为空,不能取出数据!");
        }
        front++;//让front后移
        return arr[front];
    }

    //显示队列所有数据
    public void showQueue(){
        //遍历
        if (isEmpty()){
            System.out.println("队列空的,没有数据");
            return;
        }
        for (int i = 0; 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];
    }

}

问题与优化
1)目前数组使用一次就不能用,没有达到复用的效果
2)将这个数组使用算法,改进成一个 环形的队列 取模:%

环形队列

对前面的数组模拟队列的优化,充分利用数组。因此将数组看做是一个环形的。(通过取模的方式来实现即可)
分析:
1)尾索引的下一个为头索引时表示队列满,即将队列容量空出一个作为约定,这个在做判断队列满的时候需要注意(rear + 1) % maxSize == front 【满】
2)rear == front 【空】
3)分析示意图:
在这里插入图片描述
思路如下:

  1. front变量的含义做一个调整:front就指向队列的第一个元素,也就是说arr[front]就是队列的第一个元素front的初始值=0
  2. rear变量的含义做一个调整:rear指向队列的最后一个元素的后一个位置。因为希望空出一个空间散为约定.rear的初始值=0
  3. 当队列满时,条件是(rear +1) %maxSize = front【满】
  4. 对队列为空的条件,rear== front【空】
  5. 当我们这样分析,队列中有效的数据的个数(rear + maxSize - front)%maxSize // rear = 1 front =06
  6. 我们就可以在原来的队列上修改得到一个环形队列
    代码实现
public class CircleArrayQueue {
    public static void main(String[] args) {
        //测试
        System.out.println("测试数组模拟环形队列的案例");
        //创建一个环形队列
        CircleArray arrayQueue1 = new CircleArray(4);//说明设置4,其队列的有效数据最大值是3
        char key = ' ';//接受用户输入
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        //输出一个菜单
        while (loop){
            System.out.println("s(show):显示队列");
            System.out.println("e(show):退出程序");
            System.out.println("a(show):添加数据");
            System.out.println("g(show):从队列取出数据");
            System.out.println("h(head):查看队列头数据");
            key = scanner.next().charAt(0);//接受一个字符
            switch(key){
                case 's'://显示数据
                    arrayQueue1.showQueue();
                    break;
                case 'a'://添加数据
                    System.out.println("请输入一个数");
                    int value = scanner.nextInt();
                    arrayQueue1.addQueue(value);
                    break;
                case 'g'://取出数据
                    try {
                        int res = arrayQueue1.getQueue();
                        System.out.printf("取出的数据是%d\n",res);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h'://查看队列头的数据
                    try{
                        int res = arrayQueue1.headQueue();
                        System.out.printf("队列头的数据是%d\n",res);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e'://退出
                    scanner.close();
                    loop = false;
                    break;
            }
        }
        System.out.println("程序退出");
    }
}

class CircleArray{
    private int maxsize;//表示数组最大容量
    private int front;//就是指向队列的第一个元素,arr[front]     //初始值为0
    private int rear;//指向队列的最后一个元素位置再+1     //初始值0
    private int[] arr;//该数据用于存放数据,模拟队列
    public CircleArray(int arrMaxSize){
        maxsize = arrMaxSize;
        arr = new int[maxsize];
        front = 0;
        rear = 0;
    }
    //判断队列是否满
    public boolean isFull(){
        return (rear + 1) % maxsize == front;
    }

    //判断队列是否为空
    public boolean isEmpty(){
        return rear == front;
    }

    //添加数据到队列
    public void addQueue(int n){
        //判断队列是否满
        if (isFull()){
            System.out.println("队列已满,不能加入!!!");
            return;
        }
        //直接将数据加入
        arr[rear] = n;
        //将rear后移,这里必须考虑取模
        rear = (rear + 1) % maxsize;
    }

    //获取队列的数据,出队列
    public int getQueue(){
        //判断队列是否空
        if(isEmpty()){
            //通过抛出异常
            throw new RuntimeException("队列为空,不能取出数据!");
        }
        // 这里需要分析出front是指向队列的第一个元素
        //1.先把front对应的值保存到一个临时变量
        //2.将front后移,要考虑取模
        //3.将临时保存的变量返回
        int value = arr[front];
        front = (front + 1) % maxsize;
        return value;
    }

    //显示队列所有数据
    public void showQueue(){
        //遍历
        if (isEmpty()){
            System.out.println("队列空的,没有数据");
            return;
        }
        //思路:从front开始遍历,遍历多少个元素
        //
        for (int i = front; i < front + size(); i++) {
            System.out.printf("arr[%d]=%d\n",i % maxsize,arr[i % maxsize]);
        }
    }

    //求出当前队列有效数据的个数
    public int size(){
        return (rear - front + maxsize) % maxsize;
    }

    //显示队列的头数据,注意不是取出数据
    public int headQueue(){
        //判断
        if (isEmpty())
            throw new RuntimeException("队列为空");
        return arr[front];
    }
}

结语

本文的内容主要是Java数据结构与算法中的稀疏数组和队列,大家如果感兴趣可以点点赞,关注一下,你们的支持是我最强大的动力,非常感谢您的阅读(❁´◡`❁)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/175304.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第五届字节跳动青训营 前端进阶学习笔记(七)HTTP协议入门

文章目录前言HTTP协议概述1.输入网址到页面加载完成中间发生了什么2.HTTP协议3.HTTP协议的发展历程4.HTTP报文结构&#xff08;1&#xff09;HTTP请求报文&#xff08;2&#xff09;HTTP响应报文5.请求方法&#xff08;1&#xff09;安全的方法&#xff08;2&#xff09;幂等6.…

表单标签的学习

表单标签的学习 textarea textarea标签来表示多行文本框&#xff0c;又叫做文本域。与其它 标签不同&#xff0c; textarea标签是单闭合标签&#xff0c;它包含起始标签和结束标签&#xff0c;文本内容需要写在两个标签中间。 input input type“text” 表示文本框 &#xff…

CSS入门学习笔记+案例

目录 一、 CSS的基础 1、快速了解 2、CSS应用方式 ①在标签上 ②在head标签中写style标签 ③写到文件中 二、CSS的选择器 1、ID选择器 2、类选择器 3、标签选择器 4、属性选择器 5、后代选择器 三、样式覆盖 四、CSS的样式 1、高度和宽度 2、块级和行内标签 3、字体…

七大排序---详细介绍

插入排序从第二个数&#xff0c;往前面进行插入&#xff0c;默认第一个数字有序&#xff0c;插入第二个&#xff0c;则前两个都有序了&#xff0c;一个一个往后选择数字&#xff0c;不断向前进行插入直接插入排序时间复杂度&#xff1a;最好情况&#xff1a;全部有序&#xff0…

决策树应用

使用Python中的sklearn中自带的决策树分类器DecisionTreeClassifier import sklearn clf sklearn.tree.DecisionTreeClassifier(criterionentropy)sklearn中只实现了ID3与CART决策树&#xff0c;所以我们暂时只能使用这两种决策树&#xff0c;在构造DecisionTreeClassifier类…

计算机视觉OpenCv学习系列:第六部分、图像操作-2

第六部分、图像操作-2第一节、图像几何形状绘制1.几何形状2.填充、绘制与着色3.代码练习与测试第二节、多边形填充与绘制1.多边形绘制函数2.绘制与填充3.代码练习与测试第三节、图像像素类型转换与归一化1.归一化方法与支持2.归一化函数3.代码练习与测试第四节、图像几何变换1.…

小智学长嵌入式入门学习路线_1 C语言基础

原课程链接&#xff1a; 嵌入式开发系统学习路线 从基础到项目 精品教程 单片机工程师必备课程 物联网开发 c语言 2022追更 前言 在学习过程中&#xff0c;老师提到了一个很重要的思想&#xff1a;主要从学习嵌入式的角度学习各项技能。比如c语言&#xff0c;语法有很多&…

【Java|golang】1807. 替换字符串中的括号内容

给你一个字符串 s &#xff0c;它包含一些括号对&#xff0c;每个括号中包含一个 非空 的键。 比方说&#xff0c;字符串 “(name)is(age)yearsold” 中&#xff0c;有 两个 括号对&#xff0c;分别包含键 “name” 和 “age” 。 你知道许多键对应的值&#xff0c;这些关系由…

Linux基本功系列之chmod命令实战

文章目录一. chmod命令介绍二. 语法格式及常用选项三. 参考案例3.1 对全部用户增加写的权限3.2 所有用户减去读的权限3.3 给文件的所有者和所有组加上读写权限3.4 设置所有用户为读写执行的权限3.5 文件拥有着为rwx&#xff0c;所属组为rw&#xff0c;其它为r3.6 去掉所有者的r…

高级Spring之ApplicationContext功能

第一步&#xff0c;我们先来看这个接口的内部结构&#xff0c;了解别人的内部&#xff0c;知己知彼&#xff0c;百战不殆&#xff1a; 这个接口的扩展功能主要体现在它继承的四个接口上&#xff1a; MessageSource&#xff1a;国际化功能 ResourcePatternResolver: 资源访问功…

第23章_Tomcat和JavaEE入门

一、JavaEE简介什么是JavaEEJavaEE&#xff08;Java Enterprise Edition&#xff09;&#xff0c;Java企业版&#xff0c;是一个用于企业级web开发平台。最早由Sun公司定制并发布&#xff0c;后由Oracle负责维护。JavaEE平台规范了在开发企业级web应用中的技术标准.在JavaEE平台…

Acwing——第 87 场周赛

题目链接 4797. 移动棋子 4798. 打怪兽 4799. 最远距离 题目描述 4797. 移动棋子 给定一个 5 行 5 列的方格矩阵&#xff0c;其中一个方格中有一个棋子。 现在&#xff0c;我们希望将棋子移动至矩阵的最中心方格中&#xff0c;即将其移动至矩阵的第 3行第 3列方格中。 每次…

8种时间序列分类方法总结

对时间序列进行分类是应用机器和深度学习模型的常见任务之一。本篇文章将涵盖 8 种类型的时间序列分类方法。这包括从简单的基于距离或间隔的方法到使用深度神经网络的方法。这篇文章旨在作为所有时间序列分类算法的参考文章。 时间序列定义 在涵盖各种类型的时间序列 (TS) 分…

分布式锁与实现(一)-为什么需要分布式锁

1 在开发中的锁是什么 在计算机科学中&#xff0c;锁是在执行多线程时用于强行限制资源访问的同步机制&#xff0c;即用于在并发控制中保证对互斥要求的满足。 在java中我们有两种资源控制方式Synchronized与AQS 1.2 基于Synchronized实现的锁控制 Synchronized是java提供的一…

JDK 8新特性之Lambda表达式

目录 一&#xff1a;使用匿名内部类存在的问题 Lambda表达式写法,代码如下&#xff1a; 二&#xff1a;Lambda的标准格式 三&#xff1a;Lambda的实现原理 四&#xff1a;Lambda省略格式 五&#xff1a;Lambda的前提条件 六&#xff1a;函数式接口 七&#xff1a;Lambd…

05回溯法

文章目录装载问题回溯算法优化算法构造最优解0-1背包问题批处理作业调度问题图的M着色问题N皇后问题最大团问题回溯算法实际上一个类似枚举的搜索尝试过程&#xff0c;主要是在搜索尝试过程中寻找问题的解&#xff0c;当发现已不满足求解条件时&#xff0c;就“回溯”返回&…

12. 字典dict类型详解

1. 基础知识 (1) 字典(dictionary)是Python中另一个非常有用的内置数据类型。 (2) 列表是有序的对象集合&#xff0c;字典是无序的对象集合。两者之间的区别在于&#xff1a;字典当中的元素是通过键来存取的&#xff0c;而不是通过偏移存取。 (3) 字典是一种映射类型&#xff…

Flowable进阶学习(三)流程、流程实例挂起与激活;启动、处理、结束流程的原理以及相关表结构与变动

文章目录流程挂起与激活流程实例挂起与激活启动、处理、结束流程的原理一、启动流程的原理启动一个流程实例时涉及到的表及表结构:ACT_RU_EXECUTION 运行时流程执行实例ACT_RU_IDENTITYLINK 运行时用户关系信息ACT_RU_TASK 运行时任务表ACT_RU_VARIABLE 运行时变量表二、处理流…

过滤器Filter总结

过滤器Filter1. 简介2. 快速入门3. 执行流程4. 使用细节4.1 拦截路径4.2 过滤器链5. 案例5.1 需求5.2 LoginFilter1. 简介 过滤器是JavaWeb三大组件之一&#xff08;Servlet、Filter&#xff0c;Listner&#xff09;&#xff1b; 作用&#xff1a; 把对资源&#xff08;servl…

Ubuntu22.04 安装 ssh

文章目录Ubuntu22.04 安装 ssh一、 环境配置二、 启动远程连接三、 开放端口四、 远程连接Ubuntu22.04 安装 ssh 一、 环境配置 安装 Ubuntu 系统后&#xff0c;我们首先需要配置管理员 root 用户&#xff1a; sudo passwd root然后&#xff0c;进行软件源的更换&#xff1a…