【数据结构】Java实现数据结构的前置知识,时间复杂度空间复杂度,泛型类的讲解

news2024/11/25 7:31:04

文章目录

  • 数据结构
  • 时间复杂度、空间复杂度
  • 包装类、装箱与拆箱
  • 泛型
    • 擦除机制

数据结构

当我们在成为一名程序员的这条道路上努力的时候,我们一定经常听到这个词数据结构。那么究竟什么是数据结构呢?数据结构顾名思义,就是数据+结构,数据就是数据,结构就是用来描述或者组织数据的,为什么会有那么多种的数据结构呢?是因为日常生活中的场景是多变的,那么我们组织数据描述数据的方式也应该是多变的,所以才会有这么多的数据结构来支持我们组织数据。现在我们还不能学习数据结构,因为有一些前置的知识我们还没有学习,那么下面我们就来了解一下这些前置知识吧!

时间复杂度、空间复杂度

使用数据结构组织数据,那么如何衡量组织的好坏呢?这里我们又要引入一个词——算法,数据结构和算法是相辅相成的,那么如何衡量算法的好坏,我们就需要考虑算法的效率问题,这时我们就好考虑算法的时间复杂度、空间复杂度

时间复杂度
简单一点说,时间复杂度就是在一个算法中代码的执行次数。专业一点来说,算法的时间复杂度是一个数学函数,定量描述了该算法的运行时间,运算时间与其中语句的执行次数成正比。

如何描述时间复杂度,时间复杂度怎么算呢?我们使用大O渐进法

大O渐进法规则
1、用常数1取代运行时间中的所有加法常数
2、在修改后的运行次数函数中,只保留最高阶项
3、如果最高阶存在并且不是1,则去除与这个项目相乘的常数。
4、执行完前面三部,就得到了大O阶

因为不可能每个算法我们都在计算机上执行一下计算一下执行时间,所以我们说的时间复杂度只是粗略的计算代码的执行时间,所以才有了大O渐进法规则,去掉了那些影响不大的杂项。光说无用,下面我们来上手计算一个时间复杂度:
首先看这样一个代码:

    public static void bubble_sort(int[] arr) {
        for(int i = 0; i < arr.length - 1;i++ ) {
            for(int j = 0;j < arr.length - i - 1;j++) {
                if(arr[j] > arr[j + 1]) {
                    int tmp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = tmp;
                }
            }
        }
    }

这个代码的时间复杂度怎么算呢?我们可以将arr.length 看做n,那么最外层循环需要执行的次数就是n - 1次,内层循环每次执行的次数n -1、n - 2 ...... 1,是一个等差数列,那么要求这个算法的时间复杂度就是求他代码的执行次数,也就是要求n -1、n - 2 ...... 1这个等差数列的前n项和,之后再通过大O渐进法进行化简,所以通过计算我们可以得出:该算法的时间复杂度为O(n^2)

  public static int binarySearch(int[] arr,int num) {
        int left = 0;
        int right = arr.length - 1;

        while(left <= right) {
            int mid = (right - left)/2 + left;
            if(arr[mid] > num) {
                right = mid - 1;
            }else if(arr[mid] < num) {
                left = mid + 1;
            }else {
                return mid;
            }
        }
        return -1;
    }

上面这个算法的时间复杂度怎么算呢?我们光看代码是看不出来的,计算时间复杂度不只需要看代码还需要结合思想,我们通过读代码发现这是一个二分查找,我们需要结合他的思想找到相应的规律计算出代码的执行次数:二分查找每一次查找会舍弃一半的数据,当我们只有两个数据的时候,我们需要查找的次数为两次,第一次舍弃一半的数据,第二次找到数据。当有4个数据的时候,我们需要查找3次,第一次舍弃两个数据,第二次舍弃一个数据,最后找到数据,当有八个数据的时候,我们需要查找4次。我们把我们获取到的数据放在一个表格当中:

数据个数查找次数
22
43
84
n???

通过观察数据我们总结出了一个公式:2^(2-1) = 2、2^(3-1) = 4 、2^(4-1) = 8也就是说2^(查找次数 - 1) = 数据个数所以我们可以算出n个数据时的查找次数并且是使用大O渐进法化简后为:O(logN)

空间复杂度:
空间复杂度是对一个算法再运行过程中临时占用存储空间的大小的量度。空间复杂度算的是变量的个数,空间复杂度也跟时间复杂度类似,也用大O渐进法

因为大多时候判断算法的效率还是计算时间复杂度,所以这里我们只简单提一下空间复杂度:我们来看这个代码:

 public static long factoral(int n) {
        return n < 2 ? n : factoral(n - 1)*n;
    }

他的空间复杂度是多少呢?因为每一次递归都会开辟内存空间-栈帧,每个栈帧中都用一个常量,所以空间复杂度为O(n)

包装类、装箱与拆箱

在Java中我们说一切皆对象,难道基本数据类型也是对象嘛?虽然他们不是对象,但Java中为每个基本数据类型提供了包装类。

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean
   public static void main(String[] args) {
        int num = 1;
        Integer i = Integer.valueOf(num);
        Integer i2 = new Integer(num);

        int num2 = i.intValue();

        System.out.println(i + " " + i2+ " " + num2);
    }

上图就是装箱和拆箱的操作,我们发现很复杂,为了简便我们代码的编写Java为我们提供了自动装箱和自动拆箱的操作。

   public static void main(String[] args) {
        Integer i = 10;
        int num = i;
    }

这样也可以实现装箱和拆箱的操作。了解完装箱和拆箱我们来看一道面试题:

    public static void main(String[] args) {
        Integer a = 127;
        Integer b = 127;

        Integer c = 128;
        Integer d = 128;

        System.out.println(a == b);
        System.out.println(c == d);
    }

上面这行代码的输出的结果什么呢?兄弟们可能会觉得包装类是引用数据类型,所以==比较的是引用指向对象的地址,所以abcd都不相同,输出两个false结果真的是这样嘛?
在这里插入图片描述
结果和我们所推测的并不相同,这是为什么呢?在自动装箱时同样会调用Integer类的valueOf()方法,所以我们去看看源码的逻辑是怎样的
在这里插入图片描述
当我们的形参在这个IntegerCache.low IntegerCache.high之间就不会new一个新对象,而超过这个范围的数据就需要重新new一个对象。所以 Integer a = 127; Integer b = 127;并没有重新创建对象,所以a == b输出的true
在这里插入图片描述

泛型

package demo1;

class Myarray {
    public String[] array = new String[3];
    public int[] array1 = new int[3];

    public String getArray(int pos) {
        return array[pos];
    }

    public void setArray(String array,int pos) {
        this.array[pos] = array;
    }

    public int getArray1(int pos) {
        return this.array1[pos];
    }

    public void setArray1(int array1,int pos) {
        this.array1[pos] = array1;
    }
}
public class Test {
    public static void main(String[] args) {
        Myarray myarray = new Myarray();
        myarray.setArray("abc",0);
        myarray.setArray1(10,0);

        System.out.println(myarray.getArray(0));
        System.out.println(myarray.getArray1(0));
    }
}

我们来看上面的这个代码,我们发现这样创建数组非常的麻烦,每个类型的数组都要写一份get set方法。我们可不可以写一个数组让他可以存储任意类型的数据呢?在之前我们提到了装箱和拆箱的概念,所有基本类型都又对应的包装类,而在Java中所有类的父类是Object类,我们可不可以使用Object去创建数组呢?
在这里插入图片描述
虽然我们在存储数据时编译通过了并没有报错,但是当我们去访问数据时,编译报错,原因如下图。
在这里插入图片描述
所以这样非常不好,因为如果数组中有非常多的元素,难道我需要记住所有元素的类型嘛?显然是不现实的,那如何解决问题呢?所以泛型就要出场了,泛型的主要目的:就是指定当前的容器,要持有什么类型的对象,让编译器去做检查

泛型的语法:
创建:
class 泛型类名称<类型参数列表> { }
使用:
泛型类<类型参数>变量名 = new 泛型类<类型实参>(构造方法);

我们可以对上面的代码进行修改:

package demo2;

import java.util.Arrays;

class Myarray<T> {
    public T[] array = (T[])new Object[3];

    public void setArray (T t,int pos) {
        this.array[pos] = t;
    }

    public T getArray (int pos ) {
        return this.array[pos];
    }
    @Override
    public String toString() {
        return "Myarray{" +
                "array=" + Arrays.toString(array) +
                '}';
    }
}
public class Test {
    public static void main(String[] args) {
        Myarray<Integer> myarray = new Myarray<>();
        myarray.setArray(10,0);
        myarray.setArray(20,1);
        System.out.println(myarray);


        Myarray<String> myarray1 = new Myarray<>();
        myarray1.setArray("abc",0);
        myarray1.setArray("def",1);
        System.out.println(myarray1);

    }
}

这样我们就可以实现我们的需求了。

擦除机制

说了这么多,泛型类究竟是如何编译的呢?我们去看一看源码:
在这里插入图片描述
我们发现在编译的过程中所有的泛型T被替换成了Object类,这种机制我们称为:擦除机制,运行时既然没有泛型的概念,那泛型究竟起了什么作用呢?

泛型的作用:
1、储存数据的时候,可以帮助我们进行自动的类型转换。
2、在读取元素时,可以帮助我们进行类型转换。
3、泛型可以将数据类型参数化,进行传递。

在这里插入图片描述
那么既然所有的T都会被替换为Object我们在创建数组时public T[] array = (T[])new Object[3];这个语句是否完美呢?我们是不是可以直接public Object[] array = new Object[3];
在这里插入图片描述
泛型其实是一个比较复杂的语法,我们现在只进行简单的了解,在之后的学习中我们还需要把他拿出来进行讲解。

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

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

相关文章

[附源码]计算机毕业设计JAVA校园快递管理系统

[附源码]计算机毕业设计JAVA校园快递管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybati…

vtkjs中Sample Distance功能

通过 SetSampleDistance () 来设置每条射线的采样步长&#xff0c;默认值为1&#xff0c;单位为世界坐标系单位&#xff0c;数值越小越精细 通过 SetImageSampleDistance () 来设置图像采样距离&#xff0c;默认值为1&#xff0c;即投射光线的间隔数值越小越精细 核心代码如下…

【OpenCV-Python】教程:3-10 直方图(2)直方图均衡

OpenCV Python 直方图均衡化 【目标】 理解直方图均衡化提升图像的对比度 Histogram Equalization ??? 将图像的直方图拉均衡一些&#xff0c;分散一些&#xff1b;可以提升对比度。 【代码】 通过上面的图像可以看出&#xff0c;高亮度区域较少&#xff0c;需要分散该图像…

Java HashMap 的扩容因子为什么是 0.75

所谓的加载因子&#xff0c;也叫扩容因子或者负载因子&#xff0c;它是用来进行扩容判断的。 假设加载因子是0.5&#xff0c;HashMap初始化容量是16&#xff0c;当HashMap中有16 * 0.58个元素时&#xff0c;HashMap就会进行扩容操作。 而HashMap中加载因子为0.75&#xff0c;…

pandas 100题

文章目录1.将下面字典创建为DataFrame2.提取含有字符串“python”的行3.输出df所有列名4.修改第列名5.统计grame列中每种编程语言出现的次数6 将空值用上下值的平均值填充7 列值大于3的数8 去重列9 计算列平均值10 将列转换列表11 保存到excel12 查询行列13 列值大于3小月7的值…

【Spring】编程式事务的应用场景理解

前言 我们经常在使用Spring全家桶开发JavaEE项目的时候&#xff0c;一想到事务就会习惯性的使用声明式注解Transactional,由Spring框架帮你做AOP实现事务的回滚&#xff0c;但是声明式事务恰恰比较方便&#xff0c;所以有些场景下并不好用&#xff0c;接下来我来举一个例子&am…

服务器下载mmdetection

1.申请账号密码 找实验室有root权限的同学创建一个账号密码 2.命令行中敲&#xff1a;ssh服务器账号&#xff0c;然后输入自己的服务器密码&#xff08;确认自己是否处于校园网环境&#xff0c;如果不在的话记得连vpn&#xff09; 3.命令行敲cd /切换到根目录然后ls查看服务…

通过SCADA实现KPI分析和预测性维护远比想象中简单

一、前言 随着工业发展的不断进步&#xff0c;越来越多的企业开始注重KPI分析和预测性维护。通过数据分析实现智能制造已经成为不可缺少的环节。制定并分析关键绩效指标&#xff08;KPI&#xff09;是实现数据分析战略的重要一步&#xff0c;因为只有跟踪这些关键绩效指标才能…

题目1444:蓝桥杯201 4年第五届真题斐波那契

这篇文章是帮一个叫做【废柴成长中】的孩子写的。 题目&#xff1a; 这里难点应该就是在【输入为一行用空格分开的整数n m p(0<n,m&#xff0c;p<10^18)】 &#xff0c;这里一下子就把最大值干成long的最大范围了&#xff0c;很明显&#xff0c;long肯定也不行。 解析其…

[附源码]计算机毕业设计JAVA闲置物品线上交易系统

[附源码]计算机毕业设计JAVA闲置物品线上交易系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM my…

区块链工作原理(节点、层)

Users/Nodes in a Blockchain Network 在某个节点被当作区块链网络的一部分之前&#xff0c;它必须要完成以下的要求&#xff1a; 节点需要为认证过程生成公钥/私钥对节点需要与区块链网络中的其他一部分节点建立直接连接&#xff08;peer connection&#xff09;&#xff0c…

KVM虚拟机迁移

一、KVM宿主机高可用架构设计 宿主机故障&#xff0c;内部虚拟机可以不受影响&#xff0c;可以迁移走负载均衡&#xff0c;当某个宿主机压力过大&#xff0c;可以将部分虚拟机迁移到其他机器&#xff0c;降低其负载。 1.1、架构设计 1.2、实验机器 机器 IP 角色 node1 192.…

L. Paid Leave(贪心)[CCPC Finals 2021]

题目如下&#xff1a; 思路 or 题解 我们可以先只考虑第一段(两个休息日之间) 白色为休息日&#xff0c;蓝色为工作日 我们思考&#xff0c;如果在满足题意的条件下&#xff0c;如何安排额外的休息日可以使答案更优&#xff1a; 贪心可得&#xff1a;额外的休息日尽量往后安排…

RabbitMQ之TTL机制

在京东下单&#xff0c;订单创建成功&#xff0c;等待支付&#xff0c;一般会给30分钟的时间&#xff0c;开始倒计时。如果在这段时间内用户没有支付&#xff0c;则默认订单取消。 该如何实现&#xff1f; 定期轮询&#xff08;数据库等&#xff09; 用户下单成功&#xff0…

【自然语言处理(NLP)】聊天机器人模块实现

【自然语言处理&#xff08;NLP&#xff09;】聊天机器人模块实现 作者简介&#xff1a;在校大学生一枚&#xff0c;华为云享专家&#xff0c;阿里云专家博主&#xff0c;腾云先锋&#xff08;TDP&#xff09;成员&#xff0c;云曦智划项目总负责人&#xff0c;全国高等学校计算…

《异常检测——从经典算法到深度学习》20 HotSpot:多维特征 Additive KPI 的异常定位

《异常检测——从经典算法到深度学习》 0 概论 1 基于隔离森林的异常检测算法 2 基于LOF的异常检测算法 3 基于One-Class SVM的异常检测算法 4 基于高斯概率密度异常检测算法 5 Opprentice——异常检测经典算法最终篇 6 基于重构概率的 VAE 异常检测 7 基于条件VAE异常…

[附源码]计算机毕业设计JAVA鲜花销售管理系统

[附源码]计算机毕业设计JAVA鲜花销售管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybati…

【学习笔记02】node的模块化和内置模块

一、nodejs的模块化 &#x1f602; nodejs 所有的东西都是模块 &#xff08;一&#xff09;node模块的分类 1. 自定义模块&#xff1a;自己写的模块 2. 内置模块&#xff1a;nodejs提供的模块 3. 第三方模块 别人写好的东西, 上传到某一个位置(npm), 我们去 npm 去下载到我们本…

SpringBoot+MyBatis和MyBatisPlus+vue+ElementUl实现批量删除 我只能说太简单了

目录准备工作MySQL数据库表Result返回结果1、SpringBootMyBatisPlusvueElementUl实现批量删除1.1、演示GIF动态图1.2、实体类1.3、Dao接口1.4、Service接口1.5、ServiceImpl接口实现层1.6、Controller控制层1.7、Vue前端2、SpringBootMyBatisvueElementUl实现批量删除2.1、演示…

关于数据权限的设计

在项目实际开发中我们不光要控制一个用户能访问哪些资源&#xff0c;还需要控制用户只能访问资源中的某部分数据。 控制一个用户能访问哪些资源我们有很成熟的权限管理模型即RBAC&#xff0c;但是控制用户只能访问某部分资源&#xff08;即我们常说的数据权限&#xff09;使用R…