JavaDS —— 初识集合框架 + 时间/空间复杂度

news2024/11/13 9:43:48

目录

1. 初识集合框架

1.1 集合框架的初识

1.2 什么是数据结构?

2. 时间与空间复杂度

2.1 时间复杂度

2.2 大O的渐进表示法

2.3 常见时间复杂度计算举例

2.4 空间复杂度


1. 初识集合框架

1.1 集合框架的初识

什么叫集合?什么叫框架?什么又叫集合框架?这几个字该怎么理解?下来我们一起来看。

首先,在java中集合框架也被叫做容器(container),是在java.util包底下的一组接口和其实现类.

注意: 列举了常用的接口或者抽象类, 展示了集合之间的关系,这个每个集合类放在一起就叫做集合框架;这些集合类是Java官方已经写好的类,我们需要学习的就是这一个个类或者接口背后的结构是一个什么样的东西。所以我们要学习集合,就需要学习它们背后的数据结构。


1.2 什么是数据结构?

什么是数据结构?通俗来说就是数据+结构。

举个例子:我们平时日常生活中的数据:做核酸,停车场的车位号等等,那么我们就用数据结构组织这样一堆堆的数据.

数据结构有许多:单链表、二叉树、数组等等

数据结构多种多样的原因,就是面对不同的数据我们描述和组织数据的方式不同。

所以当我们把数据结构学明白了,就可以了解了整个常用集合框架背后的知识。

于是我们接下来就会学习到:顺序表、链表、二叉树、栈、队列、堆、哈希表、AVL树、红黑树、B树……

2. 时间与空间复杂度

如何衡量一个算法的好坏?

由于我们看代码好坏的角度不一样,也就是衡量标准不一样,我们得出的结果就不一样,还有,可能由于其他的一些原因也会导致每个人的结果是不一样的,比如说硬件(内存等等)、计算标准(时间长短)等等。

那么我们在这里就统一使用如下标准:使用时间和空间两个角度去衡量算法的好坏。

那么衡量一个算法好坏是时间重要还是空间重要呢?

实际上两者都是重要的,但是平时我们通常追求的是时间的快慢,其次才是空间,因为空间随着时代的发展内存的空间可使用空间越来越大,所以我们会尽可能的浪费一点空间来取换取我们的时间.

算法效率
算法效率分析分为两种:第一种是时间效率,第二种是空间效率。时间效率被称为时间复杂度,而空间效率被称作空间复杂度。 时间复杂度主要衡量的是一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额外空间,在计算机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。

2.1 时间复杂度

定义:在计算机科学中,算法的时间复杂度是一个数学函数,用于描述算法执行所耗费的时间的快慢。

理论上我们是无法计算出一个算法所运行的时间的,因为这和硬件等各种因素是有关系的,硬件不同,执行的时间也不同。

所以我们这样分析:一个算法的时间复杂度和算法当中语句所执行的次数是成正比的,也就是说,语句越多,执行的次数就越多,所浪费的时间也是成正比的。

那么我们既然不能定量的去计算出实际上执行次数的时间,但是我们可以通过函数去描述它的时间,那这个函数就跟语句执行次数有关系,所以当我们看到代码之后我们可以看一下这个代码基本语句的执行次数有多少次。

算法中的基本操作的执行次数,为算法的时间复杂度。

有了这个概念之后我们通过以下几个例子来介绍一下:

    // 请计算一下func1基本操作执行了多少次?
    void func1(int N) {
        int count = 0;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                count++;
            }
        }
        for (int k = 0; k < 2 * N; k++) {
            count++;
        }
        int M = 10;
        while ((M--) > 0) {
            count++;
        }
        System.out.println(count);
    }

可以看出, count++执行的次数是最多的;

先看第一个嵌套的 for 循环,都是0~N,那么 count++执行了多少次?
这里有n个 i ,每个 i 都走 n 次,那么所有的 i 就一共走了n^2次,即在这个 for 循环里面就是执行了 n^2 次;
第二个for:2n次;
第三个for:10次;
最终相对比较准确的是n^2 + 2n + 10.

但是我们发现,n^2 + 2n + 10只是我们语句的一个执行次数,在程序员角度,并不是以这样一个多项的表达式作为一个复杂度的,当我们的n越来越大的时候,最终算出来的值可以忽略掉这个10,那么也就是说,当n非常非常大的时候,有些东西是可以忽略掉的,于是就有了我们这样一些规则,我们把它叫做大O的渐进表示法.

2.2 大O的渐进表示法

实际中我们计算时间复杂度时,我们其实并不需要计算精确的执行次数,而只需要大概执行次数,即使用 大O的渐进表示法计算复杂度.

大O的渐进表示法
1. 用 常数1取代运行时间中的所有加法常数;
2. 在修改后的运行次数函数中,只 保留最高阶项
3. 如果最高阶项存在且不是1,则 去除与这个项目相乘的 常数。得到的结果就是大O阶。

注意: 在这里我们在计算大O阶的时候并不是看着代码求,而是需要结合数学思想求解。


补充概念:

最坏情况复杂度;最好情况复杂度;平均复杂度。
我们直接举例说明:在数组中找一个数字的时间复杂度最坏是O(n),最好是O(1),平均是n/2。

我们所接触到的最多的情况就是最坏情况时间复杂度。


2.3 常见时间复杂度计算举例

    // 计算func2的时间复杂度?
    void func2(int N) {
        int count = 0;
        for (int k = 0; k < 2 * N; k++) {
            count++;
        }    // 2n
        int M = 10;
        while ((M--) > 0) {
            count++;
        }    // 10
        System.out.println(count);
    }

func2的时间复杂度为:O(n);


    // 计算func3的时间复杂度?
    void func3(int N, int M) {
        int count = 0;
        for (int k = 0; k < M; k++) {
            count++;
        }    // M
        for (int k = 0; k < N; k++) {
            count++;
        }    // N
        System.out.println(count);
    }

func3的时间复杂度为:O(M+N);


   // 计算func4的时间复杂度?
    void func4(int N) {
        int count = 0;
        for (int k = 0; k < 100; k++) {
            count++;
        }    // 100
        System.out.println(count);
    }

func4的时间复杂度为:O(1);

注:100是常数,常数看作1(第一条规则)


    // 计算bubbleSort的时间复杂度?    最坏是时间复杂度?最好复杂度?
    void bubbleSort(int[] array) {
        for (int end = array.length; end > 0; end--) {    //【0,n】
            boolean sorted = true;
            for (int i = 1; i < end; i++) {    //n-1 n-2 …… 1(n在变导致i也在变)
                if (array[i - 1] > array[i]) {
                    swap(array, i - 1, i);
                    sorted = false;
                }
            }
            if (sorted == true) {
                break;
            }
        }
    }

注:算一下 end 的取值: [ n, n-1, n-2, ...... , n-(n-1) ]

i 的取值-> [ n-1, n-2, n-3, ... , 1, 0 ]

所以对 i 进行求和(等差数列求和),结果为:(最坏情况下if (array[i - 1] > array[i])每次都被执行)n*(n-1) / 2, 所以最坏情况下时间复杂度为O(n^2),最好情况下就是数组有序了,复杂度为O(n)。


    // 计算binarySearch的时间复杂度?
    int binarySearch(int[] array, int value) {
        int begin = 0;
        int end = array.length - 1;
        while (begin <= end) {
            int mid = begin + ((end - begin) / 2);
            if (array[mid] < value)
                begin = mid + 1;
            else if (array[mid] > value)
                end = mid - 1;
            else return mid;
        }
        return -1;
    }

注:二分查找,每次“砍”一半:N -> N/2 -> N/4...;

于是:N/2^x = 1 => x = logN(以2为底N的对数)


    // 计算阶乘递归factorial的时间复杂度?
    long factorial(int N) {
        return N < 2 ? N : factorial(N - 1) * N;
    }

注:递归的时间复杂度 = 递归的次数 * 每次递归执行的次数

本题中,每次递归相当于是一个三目运算符在走,所以每次递归执行的次数是常数次1,所以对于本题来说只需要找到递归的次数就是它的时间复杂度。本题递归的次数是n-1次。

factorial的时间复杂度为:O(n);


    // 计算斐波那契递归fibonacci的时间复杂度?
    int fibonacci(int N) {
        return N < 2 ? N : fibonacci(N - 1) + fibonacci(N - 2);
    }

注:每一次递归,都会有两次“子递归”,所以递归次数就为:

2^0 + 2^1 + 2^2 + ... + 2^(n-1) = 2^n - 1次

斐波那契递归fibonacci的时间复杂度为O(2^n)

总结:
复杂度的计算需要通过结合代码的思想来做的。不能光靠代码来给出复杂度。

2.4 空间复杂度

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度 。空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法。

    // 计算bubbleSort的空间复杂度?完成这个算法临时空间的大小
    void bubbleSort(int[] array) {
        for (int end = array.length; end > 0; end--) {
            boolean sorted = true;
            for (int i = 1; i < end; i++) {
                if (array[i - 1] > array[i]) {
                    swap(array, i - 1, i);
                    sorted = false;
                }
            }
            if (sorted == true) {
                break;
            }
        }
    }

bubbleSort的空间复杂度为O(1),因为没有让临时空间出现增加的情况。

如果修改以上代码:

    // 计算bubbleSort的空间复杂度?完成这个算法临时空间的大小
    void bubbleSort(int[] array) {
        for (int end = array.length; end > 0; end--) {
            int tmp = new int[array.length];//->拷贝array这个数组里面的数组
            boolean sorted = true;
            for (int i = 1; i < end; i++) {
                if (array[i - 1] > array[i]) {
                    Swap(array, i - 1, i);
                    sorted = false;
                }
            }
            if (sorted == true) {
                break;
            }
        }
    }

复杂度就变为O(n);

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

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

相关文章

用友NC Cloud uploadChunk任意文件上传漏洞复现 [附POC]

文章目录 用友NC Cloud uploadChunk任意文件上传漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 用友NC Cloud uploadChunk任意文件上传漏洞复现 [附POC] 0x01 前言 免责声明&#xff1a;请勿利…

敏捷DevOps专家王立杰:端到端DevOps持续交付的5P法则 | IDCF

今天有一个流行的英文缩写词用来刻画这个风云变幻的时代&#xff1a;VUCA&#xff08;乌卡时代&#xff09;。四个英文字母分别表示动荡性&#xff08;Volatility&#xff09;、不确定性&#xff08;Uncertainty&#xff09;、复杂性&#xff08;Complexity&#xff09;和模糊性…

【精选】构建智能木材计数系统:深度学习与OpenCV完美结合(详细教程+源码)

1.研究背景与意义 随着科技的不断发展&#xff0c;计算机视觉技术在各个领域中得到了广泛的应用。其中&#xff0c;卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;作为一种强大的深度学习模型&#xff0c;已经在图像识别、目标检测、人脸识…

C语言--每日五道选择题-- Day22

第一题&#xff08;注意&#xff09; 1.下列 C 代码中&#xff0c;不属于未定义行为的有&#xff1a;______。 A&#xff1a;int i0; i(i); B&#xff1a;char *p"hello"; p[1]E; C&#xff1a;char *p"hello"; char ch*p; D&#xff1a;int i0; printf(&q…

2024年湖北省水利厅的安管人员水安ABC证报考指南

2024年湖北省水利厅的安管人员水安ABC证报考指南 关于水安ABC报考&#xff0c;很多企业乃至个人都不是很清楚流程&#xff0c;叙后尘来给大家科普一下报考详细细节。2023年年度仅剩一次的报考时间定于2023年11月23日至11月28日。在这个时间段才可以网上填写报考资料&#xff0…

JOSEF信号继电器 JX-18A/2 电压 220VAC辅助电源 板后接线

JX-18/2A系列信号继电器 JX-18A/2A1信号继电器&#xff1b; JX-18A/2A2信号继电器&#xff1b; JX-18B /2A1信号继电器; JX-18B/2A2信号继电器; JX-18C/2A1信号继电器; JX-18C/2A2信号继电器; JX-18E/2A1信号继电器; JX-18E/2A2信号继电器; JX-18D/2A1信号继电器; JX…

java继承和重写(代码演示)

java中的继承和重写 概念 继承 在 Java 中&#xff0c;继承是面向对象编程中的重要概念&#xff0c;它允许一个类&#xff08;称为子类&#xff09;继承另一个类&#xff08;称为父类&#xff09;的属性和方法。子类可以继承父类的非私有属性和方法&#xff0c;并且可以添加…

C++一个关于delete的幼稚错误

分析 在项目开发中&#xff0c;遇上这么一个错误&#xff1a; 0xc00000fd stack_overflow 这是一个栈溢出的错误&#xff0c;奇怪&#xff0c;我delete怎么会提示这么一个错误呢&#xff1f; 与是问题了群&#xff1a; 总结 这个错误实在是蠢啊&#xff01; 没有细想&am…

m4s格式视频文件如何转mp4?三个方法教会你!

m4s格式是一种视频分片格式&#xff0c;它将视频文件分成多个小块&#xff0c;方便网络传输和播放。这种格式常用于流媒体服务&#xff0c;如在线视频网站、直播平台等&#xff0c;比如B站哔哩哔哩下载下来的视频就是这种格式。 方法一&#xff1a;野葱视频转换器 一款音视频转…

【UE5】蓝图

在开发过程中&#xff0c;不可避免地会有一些蓝图的操作。同时&#xff0c;蓝图也是UE很有特色的一个内容。 了解蓝图是什么&#xff08;What is BP?&#xff09; 广义上&#xff1a;蓝图是UE内置的脚本语言&#xff0c;可以书写类似代码的逻辑。&#xff08;任何可以连那种块…

代码随想录算法训练营第四十三天【动态规划part05】 | 1049. 最后一块石头的重量 II、494. 目标和、474.一和零

1049. 最后一块石头的重量 II 题目链接&#xff1a; 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 求解思路&#xff1a; 等于把石头尽量分成重量相同的两堆 动规五部曲 确定dp数组及其下标含义&#xff1a;容量为j的背包&#xff0c;最多能装…

各大电商平台双十一“狂飙”,如何选择商城系统?

今年是“双十一”的第十五年。作为各大平台和品牌的全年最重要的营销节点&#xff0c;品牌们可谓是来势汹汹&#xff0c;各种促销活动和优惠力度让人眼花缭乱。 淘天数据显示&#xff0c;天猫促销活动开售当晚&#xff0c;155个品牌开卖成交额突破1亿元&#xff1b;首小时内7.1…

前端数组方法汇总集锦

前言 数组主要使用场景有&#xff1a; 存储和处理数据&#xff1a;数组是一种有序的数据结构&#xff0c;可以用来存储和处理多个相关的数据。在前端开发中&#xff0c;我们经常使用数组来存储和处理列表、表格、选项等数据。 循环和遍历&#xff1a;数组提供了循环和遍历的功能…

three.js学习总结超详细附带素材及源码

three.js学习总结超详细附带素材及源码 安装three.js npm install --save three引入three.js import * as THREE from threethree.js结构 three.js坐标 创建一个场景 scene场景&#xff0c;camera相机&#xff0c;renderer渲染器 创建一个场景 this.scene new THREE.Scene(…

Redis 性能管理 主从复制与哨兵模式

目录 redis性能管理 内存碎片率 如何清理内存 面试题 Redis雪崩 Redis集群大面积故障 面试&#xff1a;Redis的缓存击穿 Redis的缓存穿透 Redis的集群高可用方案 redis的主从复制 哨兵模式 redis性能管理 redis的数据缓存在内存当中 info memory #在redis数据库中查…

金蝶云星空部署包导出文件

文章目录 金蝶云星空部署包导出文件 金蝶云星空部署包导出文件 打开补丁包后&#xff0c;贴入导出文件的文件夹&#xff0c;然后按F2即可导出到目标文件夹。

软件测试工具常用的都有哪些

软件测试工具是用于辅助软件测试的软件工具&#xff0c;可以帮助测试人员执行测试用例、记录测试结果、跟踪缺陷状态等&#xff0c;提高测试效率和质量。以下是一些常见的软件测试工具&#xff1a; 一、AutoRunner自动化测试工具 AutoRunner(简称AR&#xff09;是国内自主研发…

如何防止网络被入侵?

随着互联网的普及&#xff0c;网络安全问题越来越受到人们的关注。其中&#xff0c;如何防止网络被入侵是一个重要的问题。本文将介绍一些防止网络被入侵的方法&#xff0c;帮助大家保护自己的网络安全。 一、使用强密码 强密码是防止网络被入侵的第一道防线。一个好的密码应该…

d3dcompiler_47.dll缺失怎么修复,d3dcompiler_47.dll的作用有哪些

d3dcompiler_47.dll丢失是一种常见的电脑问题。如果你遇到了这个问题&#xff0c;不要惊慌&#xff0c;下面的方法可以帮助你解决。本文将详细介绍解决d3dcompiler_47.dll丢失问题的步骤&#xff0c;让你手把手地学会。 一.解决d3dcompiler_47.dll丢失问题的步骤 解决方法一&a…

2.4G无线收发芯片 XL2400P使用手册

XL2400P 系列芯片是工作在 2.400~2.483GHz 世界通用 ISM 频段的单片无线收发芯片。该芯片集成射 频收发机、频率收生器、晶体振荡器、调制解调器等功能模块&#xff0c;并且支持一对多组网和带 ACK 的通信模 式。发射输出功率、工作频道以及通信数据率均可配置。芯片已将多颗外…