数据结构初阶(算法的复杂度 + 包装类 + 泛型)

文章目录

  • 一、算法复杂度
    • 1. 算法效率
    • 2. 时间复杂度
      • (1) O的渐进表示法
    • 3. 空间复杂度
  • 二、包装
    • 2.1 为什么会出现包装
    • 2.2 分类
    • 2.3 装箱和拆箱
      • (1)装箱/装包
      • (2)拆箱/拆箱
  • 三、泛型
    • 3.1 泛型的基本概念
    • 3.2 泛型的使用
    • 3.3 泛型的编译
    • 3.4 泛型的上界

一、算法复杂度

1. 算法效率

  • 我们一般是通过算法的复杂度去判断一个算法的好坏,其评判的标准,一般是从时间、空间两个维度来衡量,即时间复杂度和空间复杂度
  • 时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间
  • 早期,我们更看重于空间复杂度,但随着技术的发展,我们现在更看重时间复杂度

2. 时间复杂度

  • 概念
    • 算法的时间是难以高效率地测出来的,所以我们通过一个函数去定量描述算法的时间复杂度
      • 不能掐表,因为运行的时间和电脑的硬件是有关系的
      • 时间是要运行的时候才能体现出来,不能每次都上机测试,所以时间复杂度是一个分析方式
      • 时间复杂度是一个估算的值
  • 计算:先算出执行的次数,将其转化为函数之后,用O的渐进表示法表示

(1) O的渐进表示法

  • 大O符号(Big O notation):是用于描述函数渐进行为的数学符号

  • 推导大O阶方法

    • 用常数1取代运行时间中的所有加法常数。
    • 在修改后的运行次数函数中,只保留最高阶项。
    • 如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶
  • 效果:去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数

  • 结果形式

    • 最坏情况:任意输入规模的最大运行次数(上界)
    • 平均情况:任意输入规模的期望运行次数
    • 最好情况:任意输入规模的最小运行次数(下界)
      在实际中一般情况关注的是算法的最坏运行情况

3. 空间复杂度

概念:对一个算法在运行过程中临时占用存储空间大小的量度,在实际上算的是变量的个数
计算方式:求出变量的个数后,用大O渐进表示法表示

二、包装

2.1 为什么会出现包装

    在Java中,由于基本数据类型不是继承与Object的,为了在泛型代码中可以支持基本类型,Java中每一个基本数据类型都有一个对应的包装类
    对于基本类型来说,包装类中的属性和方法,可以让数据的转换等使用方法更加方便

2.2 分类

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

除了 Integer 和 Character ,其余基本类型的包装类都是首字母大写

2.3 装箱和拆箱

(1)装箱/装包

  • 概念:基本类型------------>包装类型
  • 实现方式:新建一个 包装类型对象,将基本数据类型的值放入对象的某个属性中
  • 代码示例:
public static void main1(String[] args) {
    int a = 10;
    int b = 20;
    //自动装箱
    Integer i = a;//与Integer i = Integer.valueOf(a);是一样的,JVM会帮着调用一个valueOf方法
    Integer iiii = (Integer) b;

    显示装箱
    int c = 30;
    int d = 40;
    Integer iii = Integer.valueOf(c);//使用类调用的,说明是被static修饰的

    Integer ii = new Integer(d);
}

❤️Integer.valueOf方法介绍

  • 源代码
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
  • 含义
    • 如果该 int 类型的值在-127 ~ 128 之间,会缓存在一个数组中,每个数对应的下标是 i + (-IntegerCache.low)
    • 如果不是在-127 ~ 128 之间,会new一个新的对象

(2)拆箱/拆箱

  • 概念:包装类型------------>类型类型
  • 实现方式:将包装类型对象的值取出,放到一个基本数据类型中
  • 代码示例
    public static void main2(String[] args) {
        Integer a = 10;
        //自动拆箱
        int ii = a;
        int iii = (int)a;

        //显示拆箱
        int i = a.intValue();   //用对象调用,说明这是一个类中的方法
        float f = a.floatValue();
    }

三、泛型

3.1 泛型的基本概念

  • 什么是泛型
    泛型就是适用于许多类型,从代码上讲,就是将类型作为参数
  • 泛型的目的
    虽然我们希望泛型适用于许多类型(什么类型的都可以接收),但是如果同时存有不同类型,数据的拿取就会变得很麻烦。
    所以更多情况下,我们还是希望泛型只能持有一种数据类型。
    泛型的主要目的,就是指定当前的容器,要持有什么类型的对象,在编译的时候,让编译器去做检查类型和类型的转换
  • 注意
    Java的泛型机制是在编译级别实现的,编译器生成的字节码在运行期间并不包含泛型的类型信息

3.2 泛型的使用

<>里面一定是个引用类型

语法(1)------------>定义一个泛型类
class 泛型类名称<类型形参列表>{
       //这里可以使用类型参数
}

语法(2)------------>定义一个继承某个类的泛型类
class 泛型类名称<类型形参列表> extends 继承类(这里可以使用类型参数){
       //可以只使用部分类型参数
}

语法(3)------------>定义一个泛型类引用
泛型类<类型实参>变量名;      

语法(4)------------>实例化一个泛型类对象
new 泛型类<类型实参>(构造方法实参);      

语法(5)------------>裸类型
概念:是一个泛型类但是没有带着类型实参,意味着什么都能放,那取出来还要强转
注意:不要主动去使用裸类型,因为这是为了兼容老版本保留的机制

  • 写法注意
class MyArray4<T>{  //定义一个泛型类,T这边的效果就是传什么就是什么,T表示的是这是一个占位符,表示当前类是一个泛型类
    public Object[] objects = new Object[10];   //最好的写法
    //public T[] objects2 = new T[5];   错误,数组在new的时候,后面一定要跟一个具体的类型
    public T[] objects3 = (T[])new Object[5];   //这种可以,但是不好

    public Object getPos(int pos){
        return objects3[pos];
    }
}

public class Test {
    public static void main(String[] args) {
        MyArray<Integer> myArray = new MyArray<>();   //语法3+语法4,Integer表示指定传的是int类型的
        MyArray<Integer> myArray1 = new MyArray<Integer>();   //裸类型
        //效果和上一行是一样的,实例化对象那边的<>中的包装类型是可以省略的,因为可以根据上下文推导出实例化所需要的类型实参

        //数组在new的时候,后面一定要跟一个具体的类型,因为T这种占位符在运行的时候是不知道是什么的
        //T[] ts = new T[5];
    }
}

  • 规范写法(还是用Object接收,取的时候,强制转换就好了)
class MyArray1<T>{
    public Object[] objects = new Object[10];

    public T getPos(int pos){
        return (T)objects[pos];
    }

    public void setPos(int pos, T val){
        objects[pos] = val;
    }
}

public class Test{
    public static void main(String[] args){
        MyArray1<Integer> myArray1 = new MyArray1<>();
        myArray1.setPos(0, 20);
        System.out.println(myArray1.getPos(0));

        MyArray1<String> myArray2 = new MyArray1<>();
        myArray2.setPos(0, "aaa");
        System.out.println(myArray2.getPos(0));
    }
}

在这里插入图片描述

3.3 泛型的编译

泛型的编译中需要遵循一个擦除机制
擦除机制就是在编译的过程当中把所有的T替换成Object这种机制,所以在运行的时候是没有T的,即没有泛型的概念

  • 既然T[5] = new T[5]在编译的时候,会把T替换成Object,不是相当于Object[5] = new Object[5]吗?为什么是错的?
    • :因为数组在new的时候后面一定需要的是一个具体的类型
  • 类型擦除,一定是把T变成Object吗?

❤️为什么不能实例化泛型数组
错误示例

class MyArray<T>{
	public T[]array = (T[])new Object[10];

	public T getPos(int pos){
		return this.array[pos];
	}
	
	public void setVal(int pos, T val){
		this.arrar[pos] = val;
	}
	
	public T[] getArray(){
		return array;
	}
}

public class Main{
	public static void main(String[]args){
		MyArrar<Integer> myArray1 = new MyArray<Integer>();
		Integer[] intgers = myArray1.getArray();   //不知道该用什么接收
	}
}

会报错,返回的Object数组里面,可能存放的是任何的数据类型,运行的时间直接传给Integer等类型的数组,会被编译器认为不安全
那怕是强转都不行,因为Object类型表示这里面什么类型都可以放,即可能有char、String等类型,全部都转为Integer会不安全

正确解法

class MyArray1<T>{
    public Object[] objects = new Object[10];

    public T getPos(int pos){
        return (T)objects[pos];
    }

    public void setPos(int pos, T val){
        objects[pos] = val;
    }

    public Object[] getArray(){
        return objects;
    }
}

public class Test{
    public static void main(String[] args){
        MyArray1<Integer> myArray1 = new MyArray1<>();
        myArray1.setPos(0, 20);
        System.out.println(myArray1.getPos(0));

        MyArray1<String> myArray2 = new MyArray1<>();
        myArray2.setPos(0, "aaa");
        System.out.println(myArray2.getPos(0));
    }
}

3.4 泛型的上界

概念:在定义泛型类时,对传入的类型变量通过类型边界作一定的约束
语法
         class 泛型类名称<类型形参 extends 类型边界>{
         }
示例
         class MyArray< E extends Number>{
         }
         E要么是Number的子类,要么就是Number

代码示例 ------------------> 写一个泛型类,求数组中的最大值

<>里面的一定是个引用类型,而引用类型是不可以通过大于和小于进行比较的,因为T在编译的时候会变成Object类,Object类是所有类的父类,本身并没有关联Comparable接口,所以这个泛型类要关联Comparable接口

class Alg<T extends Comparable<T>>{   //擦除为一个实现了这个接口的类型
    public T findMax(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            //引用类型不可以通过 大于和小于进行比较
            if(max.compareTo(array[i]) < 0 ) {
                max = array[i];
            }
        }
        return max;
    }
}

public class Test{
    public static void main(String[] args){
        Alg<Integer> alg = new Alg<>();
        Integer[] array = {1, 5, 2, 7, 19, 4};
        Integer max = alg.<Integer>findMax(array);  //可以通过array类判断传的是什么类型的数据
        System.out.println(max);
    }
}
//这是用静态泛型方法去写
class Alg2 {
    public static<T extends Comparable<T>> T findMax(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(max.compareTo(array[i]) < 0 ) {
                max = array[i];
            }
        }
        return max;
    }
}
public class Test2 {

    public static void main(String[] args) {
        Integer[] array = {1,5,2,7,19,4};
        Integer max = Alg2.<Integer>findMax(array);//可以通过array类判断传的是什么类型的数据
        System.out.println(max);
    }
}

在这里插入图片描述

泛型方法

语法
方法限定符<类型形参列表> 返回值类型 方法名称(形参列表){
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Elastic (ELK) Stack 实战教程】10、ELK 架构升级-引入消息队列 Redis、Kafka

目录 一、ELK 架构面临的问题 1.1 耦合度过高 1.2 性能瓶颈 二、ELK 对接 Redis 实践 2.1 配置 Redis 2.1.1 安装 Redis 2.1.2 配置 Redis 2.1.3 启动 Redis 2.2 配置 Filebeat 2.3 配置 Logstash 2.4 数据消费 2.5 配置 kibana 三、消息队列基本概述 3.1 什么是…

Spring Cloud Gateway: 网关

文章目录 网关Hello world路由: Route谓词: Predicate过滤器: FilterGateway实现限流: RequestRateLimiter过滤器使用Gateway实现服务降级 自定义全局过滤器GateWay中执行流程 网关 API网关就是实现了前端项目和服务端项目之间的统一入口 Nginx实现的是用户和前端项目之间调用…

Spring AOP

目录 AOP 为什么使用AOP Spring AOP AOP的组成 实现Spring AOP AOP表达式 Spring AOP的实现原理 在介绍Spring AOP之前需要先介绍AOP AOP AOP(面向切面编程)就像我们之前学习的OOP(面向对象编程)它是一种思想,它是对某一类事情的集中处理,比如用户登录的校验,在没学AOP…

BUUCTF-rip

https://www.cnblogs.com/refrain-again/p/15001283.html 看了这个文章 我起码能理解我们栈溢出的目的 在做题之前 我们需要先理解 栈的存储方法 从上往下看 就能理解入栈 说回这道题目 为什么这道题目是栈溢出 1.查看基本信息 checksec file 是kali下的elf文件 相当于w…

场景搭建、素材库、在线标绘等,四维轻云地理空间数据云管理平台新增了这些功能

四维轻云是一款地理空间数据云管理平台&#xff0c;具有地理空间数据在线管理、展示及分享等功能。在四维轻云平台中&#xff0c;用户可以不受时间地点的限制&#xff0c;随时随地管理、查看及分享各类地理空间数据。 为了更好地满足用户需求和进行地理空间数据在线管理&#…

Kafka源码分析之Producer数据发送流程(四)

概述 书接上回的producer发送流程&#xff0c;在准备工作完成后&#xff0c;kafka的producer借助Sender和KafkaClient两大组件完成了数据的发送。其底层封装了java的NIO的组件channle以及selector&#xff0c;对于NIO组件不太熟悉的同学可以自行查询相关文档。 下面我整理了k…

gnome换回纵向切换工作区

效果&#xff1a; 思路 最新的debian / ubuntu中用的gnome 4.x&#xff0c;工作区切换变成了左右切换&#xff0c;习惯了上下&#xff0c;真的很不舒服。 而且优化选项里也把设置开关取消掉了&#xff0c;解决方案是使用Vertical overview这个扩展&#xff1a; ## 安装扩展管…

「Bug」OpenCV读取图像为 None 分析

头一次遇到 OpenCV 无法读取图像&#xff0c;并且没有任何提示&#xff0c;首先怀疑的就是中文路径&#xff0c;因为大概率是这个地方出错的&#xff0c;但是修改完依旧是None&#xff0c;这就很苦恼了&#xff0c;分析了下出现None的原因&#xff0c;大概有以下三种情况&#…

docker安装redis

首先到dockerhub搜索redis docker pull redis docker pull redis准备redis的配置文件,因为需要redis的配置文件,这里最好去redis中文官方网站去下载一个redis,使用里面的配置文件即可. 我使用的是redis4.0.11中的配置文件 修改redis.conf配置文件 主要修改的位置如下 # bin…

如何在电脑本地下载镜像重装系统

现在网上随处可以下载操作系统&#xff0c;下载下来的是镜像系统&#xff0c;很多朋友都不知道电脑镜像重装系统是什么意思&#xff0c;怎么用镜像重装系统&#xff0c;今天小编就给大家带来了电脑镜像重装系统是什么意思的相关解答&#xff0c;一起往下看。 电脑镜像重装系统是…

react项目中自定义一个markdown编辑器

Markdown 是一种轻量级标记语言。 Markdown是一种简单的格式化文本的方法&#xff0c;在任何设备上看起来都很棒。它不会做任何花哨的事情&#xff0c;比如改变字体大小、颜色或类型——只是基本的&#xff0c;使用你已经知道的键盘符号。 它还允许人们使用易读易写的纯文本格…

UE5.1.1创建C++工程失败解决办法

闲来无事&#xff0c;更新了一下UE5.1.1&#xff0c;妈蛋创建C项目居然失败&#xff0c; 错误截图如下&#xff1a; 妈蛋&#xff0c;后面一堆乱码&#xff0c;鬼知道是啥错误&#xff01; 咋解决&#xff1f;步步高打火机&#xff0c;直接复制第一段的Running后面的代码到cmd…

【Linux系统管理进程,运行,挂起,杀死进程和crontab计划任务表的使用以及实验的心得体会】

实验 &#xff08;1&#xff09;显示本用户的进程&#xff0c;重定向到file1 top命令如果不加限制&#xff0c;默认是查看所有用户的进程情况top -u [用户名] 可以查看该用户名的所有进程 &#xff08;2&#xff09;显示本用户所有进程&#xff0c;重定向到file2 top命令如果…

打造智慧医疗新生态:互联网医院系统源码分析

在数字化时代&#xff0c;医疗行业也在不断地探索新的模式和方法&#xff0c;以更好地服务于人民群众。互联网医院系统作为一种新型医疗服务模式&#xff0c;受到了广泛的关注和热议。下文&#xff0c;小编将为大家介绍互联网医院系统的概念、特点以及如何利用互联网医院系统源…

【JAVAEE】网络原理之网络发展史

目录 &#x1f381;1. 独立模式 &#x1f383;2. 网络互连 &#x1f388;2.1 局域网 LAN ✨2.1.1 基于网线直连 &#x1f451;2.2.2 基于集线器组建 &#x1f48b;2.2.3 基于交换机组建 &#x1f457;2.2.4 基于交换机与路由器组建 &#x1f388;2.2 广域网 21世纪是一…

香橙派4LTS和树莓派4B构建K8S集群实践之一:K8S安装

目录 1. 说明 1.1 软硬件环境 1.2 设计目标 2 实现 2.1 准备工作 - 香橙派 (k8s-master-1) - 树莓派 (k8s-node-1) - 两派都要干的事 2.2 containerd 安装与设置 2.3 安装 3 遇到的问题 3.1 k8s-master-1 3.2 k8s-node-1 4 相关命令 5 Tips 6 参考 1. 说明 …

反向代理自建教程:你懂的

一、为什么需要自建反代 OpenAI提供了两种访问方式&#xff0c;一种是直接在ChatGPT网页端使用的Access Token方式&#xff0c;这种方式可以免费使用GPT-3.5模型&#xff0c;只需要登录即可使用。但缺点是不稳定&#xff0c;且无法扩展。另一种是使用API&#xff0c;注册用户可…

SpringBoot自动装配原理(附面试快速答法)

文章目录SpringBoot自动装配原理1. 从调用SpringApplication构造器方法开始2. 解析启动类4.按需装配4.1 分析dubbo自动装配5. 如果定义自己的starter6. 面试答法SpringBoot自动装配原理 之前面试被问到这个题目&#xff0c;只会答一些spi、AutoConfigration注解、Import之类的&…

询问ChatGPT的高质量答案艺术——提示工程指南(更新中……)

目录前言一、提示工程简介二、提示技巧2-1、生成法律文件2-2、添加提示技巧三、角色扮演3-1、智能手机产品描述3-2、添加角色扮演四、标准提示4-1、写一篇有关于新智能手机的评论4-2、添加标准提示、角色提示、种子词提示等等五、示例很少、或者没有示例5-1、生成一个手机配置六…

机器学习中的数学原理——过拟合、正则化与惩罚函数

通过这篇博客&#xff0c;你将清晰的明白什么是过拟合、正则化、惩罚函数。这个专栏名为白话机器学习中数学学习笔记&#xff0c;主要是用来分享一下我在 机器学习中的学习笔记及一些感悟&#xff0c;也希望对你的学习有帮助哦&#xff01;感兴趣的小伙伴欢迎私信或者评论区留言…