Java拓展--空间复杂度和时间复杂度

news2024/11/18 11:43:00

空间复杂度和时间复杂度

文章目录

  • 空间复杂度和时间复杂度
    • 空间复杂度
    • 时间复杂度
      • **评价排序算法**
      • **时间频度**
        • **什么是时间频度**
        • **忽略常数项**
        • **忽略低次项**
        • **忽略系数**
      • **时间复杂度**
        • **什么是时间复杂度**
        • **计算时间复杂度的方法**
        • **常见的时间复杂度**
      • **常见的时间复杂度**
        • **常数阶**O(1)
        • **对数阶**O(log2n)
        • **线性阶**O(n)
        • **线性对数阶**O(nlog2N)
        • **平方阶**O(n²)
        • **立方阶**O(n³)
        • K**次方阶**O(n^k)
      • **平均时间复杂度、最坏时间复杂度**
        • 排序稳定性
    • **排序术语**
    • **排序术语**

空间复杂度

简单的说就是程序运行所需要的存储空间。

一个算法的空间复杂度,也常用大 O 记法表示。

要知道每一个算法所编写的程序,运行过程中都需要占用大小不等的存储空间,算法的存储量包括:

  1. 程序本身所占空间

  2. 输入数据所占空间

  3. 辅助变量所占空间

首先,程序自身所占用的存储空间取决于其包含的代码量,如果要压缩这部分存储空间,就要求我们在实现功能的同时,尽可能编写足够短的代码。

其次,程序运行过程中输入输出的数据,往往由要解决的问题而定,即便所用算法不同,程序输入输出所占用的存储空间也是相近的。

事实上,对算法的空间复杂度影响最大的,往往是程序运行过程中所申请的临时存储空间。不同的算法所编写出的程序,其运行时申请的临时存储空间通常会有较大不同。

举例

Scanner scanner = new Scanner(System.in)
int n;
n = scanner.nextInt();
int a[10];

通过分析不难看出,这段程序在运行时所申请的临时空间,并不随 n 的值而变化。而如果将第 4 行代码改为

int a[n];

此时,程序运行所申请的临时空间,和 n 值有直接的关联。

  • 如果程序所占用的存储空间和输入值无关,则该程序的空间复杂度就为 O(1)
  • 如果随着输入值 n 的增大,程序申请的临时空间成线性增长,则程序的空间复杂度用 O(n) 表示
  • 如果随着输入值 n 的增大,程序申请的临时空间成 n2 关系增长,则程序的空间复杂度用 O(n2 ) 表示
  • 如果随着输入值 n 的增大,程序申请的临时空间成 n3 关系增长,则程序的空间复杂度用 O(n3 ) 表示

写代码我们可以用时间换空间,也可以用空间换时间。加大空间消耗来换取运行时间的缩短,加大时间的消耗换取空间,我们一般选择空间换时间。一般说复杂度是指时间复杂度。

时间复杂度

评价排序算法

评价一个算法通常从两个角度考虑

  • 执行速度
  • 占用存储空间

如果执行速度块,说明算法好。这种评价的角度称为时间复杂度

如果执行过程中占用存储空间少,说明算法好。这种评价的角度称为空间复杂度

而实际上对于用户来说时间复杂度更重要,因为时间复杂度是用户能感受到的,而空间复杂度是用户感受不到的。为了让用户感受速度,还可以用空间换时间,例如缓存(redis,memcache)技术就是用空间换时间。

时间频度

要学习时间复杂度,要先知道什么是时间频度。

什么是时间频度

**时间频度:**一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。**一个算法中的语句执行次数称为语句频度或时间****频度。**记为T(n)

例如:计算1-100所有数字之和

第一种算法:

    int sum = 0;
    int end = 100;
    for (int i = 0; i <= end; i++) {
		sum += i;
	}

​ 时间频度为:T(n+1),说明随着end值的增加,时间频度也会增加。

第二种算法:

    int total = 0;
    int end = 100;
    total = (1+end )*end /2;

​ 时间频度为:T(1),说明随着end值的增加,时间频度不会增加。

忽略常数项

时间频度的函数表:

n的值T(n)=2n+20T(n)=2*nT(n)=T(3n+10)T(n)=T(3n)
1222133
2244166
530102515
836163424
1550305545
30806010090
100220200310300
300620600910900

观察上表,发现随着n的增大,时间频度也会增大。

例如:

  • 当n为300时,2n+20的值是620
  • 当n为300时,2*n的值是600

再例如:

  • 当n为300时,T(3n+10) 的值是910
  • 当n为300时,T(3n) 的值是900

随着n的增大,时间频度的变化如下图所示:

image-20230910231331380

我们发现:

  • 2n+20 和 2n 随着n 变大,执行曲线无限接近, 20可以忽略
  • 3n+10 和 3n 随着n 变大,执行曲线无限接近, 10可以忽略

结论:时间频度的常数项可以忽略

忽略低次项

下表是一个时间频度的函数表:

n的值T(n) =2n²+3n+10T(n) =T(2n²)T(n)=T(n²+5n+20)T(n)=T(n²)
1152261
2248344
575507025
816212812464
15505450320225
30190018001070900
10020310200001052010000

观察上表,发现随着n的增大,时间频度也会增大。

例如:

  • 当n为100时,2n²+3n+10的值是20310
  • 当n为100时,T(2n²) 的值是20000

再例如:

  • 当n为100时,T(n²+5n+20) 的值是10520
  • 当n为100时,T(n²) 的值是 10000

随着n的增大,时间频度的变化如下图所示:

image-20230910231930460

我们发现:

  • 2n^2+3n+10 和 2n^2 随着n 变大, 执行曲线无限接近, 可以忽略 3n+10

  • n^2+5n+20 和 n^2 随着n 变大,执行曲线无限接近, 可以忽略 5n+20

结论:时间频度的低次项可以忽略

忽略系数

下表是一个时间频度的函数表

n的值T(3n^2+2n)T(5n^2+7n)T(n^3+5n)T(6n^3+4n)
1512610
216341856
585160150770
82083765523140
157051230345020310
302760471027150162120
100302005070010005006000400

观察上表,发现随着n的增大,时间频度也会增大。

例如:

  • 当n为100时,3n^2+2n的值是30200
  • 当n为100时,5n^2+7n的值是50700

再例如:

  • 当n为100时,n^3+5n 的值是1000500
  • 当n为100时,6n^3+4n的值是6000400

随着n的增大,时间频度的变化如下图所示:

image-20230910232400629

我们发现:

  • 5n^2+7n 和 3n^2 + 2n ,随着n值变大,执行曲线重合, 说明这种情况下, 5和3可以忽略。
  • n^3+5n 和 6n^3+4n ,随着n值变大,执行曲线分离,说明多少次方式关键。

结论:时间频度的系数可以忽略

时间复杂度

什么是时间复杂度

​ 一般情况下,算法中的基本操作语句的重复执行次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n) / f(n) 的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作 T(n)=O( f(n) ),称O( f(n)) 为算法的渐进时间复杂度,简称时间复杂度。

​ T(n) 不同,但时间复杂度可能相同。 如:T(n)=n²+7n+6 与 T(n)=3n²+2n+2 它们的T(n) 不同,但时间复杂度相同,都为O(n²)。因为时间频度中的常数项、低次向、系数都可以忽略

计算时间复杂度的方法

  1. 用常数1代替运行时间中的所有加法常数 T(n)=n²+7n+6 => T(n)=n²+7n+1

  2. 修改后的运行次数函数中,只保留最高阶项 T(n)=n²+7n+1 => T(n) = n²

  3. 去除最高阶项的系数 T(n) = n² => T(n) = n² => O(n²)

常见的时间复杂度

  • 常数阶O(1)
  • 对数阶O(log2n)线性阶O(n)
  • 线性对数阶O(nlog2n)
  • 平方阶O(n^2)
  • 立方阶O(n^3)
  • k次方阶O(n^k)
  • 指数阶O(2^n)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

说明:

  • 常见的算法时间复杂度由小到大依次为:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2 )<Ο(n3 )< Ο(nk ) <Ο(2n)
  • 随着问题规模n的不断增大,上述时间复杂度不断增大,算法的执行效率越低
  • 从图中可见,我们应该尽可能避免使用指数阶的算法

常见的时间复杂度

常数阶O(1)

无论代码执行了多少行,只要是没有循环等复杂结构,那这个代码的时间复杂度就都是O(1)

    int i = 1;
    int j = 2;
    i++;
    j++;
    int sum = i+j;

**说明:**上述代码在执行的时候,它消耗的时间并不随着某个变量的增长而增长,那么无论这类代码有多长,即使有几万几十万行,都可以用O(1)来表示它的时间复杂度。

对数阶O(log2n)

    int i = 1;
    while(i<=n) {
    i = i * 2;
    }

**说明:**在while循环里面,每次都将 i 乘以 2,乘完之后,i 距离 n 就越来越近了。

​ 假设循环x次之后,i 就大于 2 了,此时这个循环就退出了,也就是说 2 的 x 次方等于 n,那么 x = log2n也就是说当循环 log2n 次以后,这个代码就结束了。

因此这个代码的时间复杂度为:O(log2n) 。 O(log2n) 的这个2 时间上是根据代码变化的,i = i * 3 ,则是O(log3n)

线性阶O(n)

    for (int i = 1; i <=n; i++) {
        
    }

**说明:**这段代码,for循环里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变化的,因此这类代码都可以用O(n)来表示它的时间复杂度

线性对数阶O(nlog2N)

    for (int m = 1; m <=n; m++) {
        int i = 1;
        while(i<n) {
        	i = i * 2;
        }
    }

**说明:**线性对数阶O(nlogN) 其实非常容易理解,将时间复杂度为O(logn)的对数阶代码循环N遍的话,那么它的时间复杂度就是 n * O(logN),也就是了O(nlogN)。

平方阶O(n²)

    for (int i = 1; i <= n; i++) {
        for(int j=1;j <= n;j++) {
            
        }
    }

**说明:**平方阶O(n²) 就更容易理解了,如果把 O(n) 的代码再嵌套循环一遍,它的时间复杂度就是 O(n²),这段代码其实就是嵌套了2层n循环,它的时间复杂度就是O(n * n),即 O(n²) 如果将其中一层循环的n改成m,那它的时间复杂度就变成了O(m * n)。

立方阶O(n³)

相当于三层n循环,其它的类似O(n²)

K次方阶O(n^k)

O(n^k )相当于三层n循环,其它的类似O(n²)

平均时间复杂度、最坏时间复杂度

  • 平均时间复杂度:考虑各种情况及其发生的概率,得到的时间复杂度。
  • 最好时间复杂度:在最理想的情况下,执行这段代码的时间复杂度。
  • 最坏时间复杂度:在最糟糕的情况下,执行这段代码的时间复杂度。

一般讨论的时间复杂度均是最坏情况下的时间复杂度。 这样做的原因是:最坏情况下的时间复杂度是算法在任何输入实例上运行时间的界限,这就保证了算法的运行时间不会比最坏情况更长。

​ 各种排序算法的最好、最坏、平均时间复杂度如下表所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

排序稳定性

**稳定排序:**是指能保证排序前,两个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。

​ 例如,如果Ai = Aj,Ai原来在位置前,排序后Ai还是要在Aj位置前。

**不稳定排序:**排序之后在序列中相等的值的相对位置发生变化。

排序术语

  • 稳定:如果 A 原本在 B 前面,而 A=B,排序之后 A 仍然在 B 的前面。
  • 不稳定:如果 A 原本在 B 的前面,而 A=B,排序之后 A 可能会出现在 B 的后面。
  • 内排序(In-place):所有排序操作都在内存中完成。
  • 外排序(Out-place):由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行。
  • 时间复杂度: 定性描述一个算法执行所耗费的时间。
    个的前后位置顺序相同。

​ 例如,如果Ai = Aj,Ai原来在位置前,排序后Ai还是要在Aj位置前。

**不稳定排序:**排序之后在序列中相等的值的相对位置发生变化。

排序术语

  • 稳定:如果 A 原本在 B 前面,而 A=B,排序之后 A 仍然在 B 的前面。
  • 不稳定:如果 A 原本在 B 的前面,而 A=B,排序之后 A 可能会出现在 B 的后面。
  • 内排序(In-place):所有排序操作都在内存中完成。
  • 外排序(Out-place):由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行。
  • 时间复杂度: 定性描述一个算法执行所耗费的时间。
  • 空间复杂度:定性描述一个算法执行所需内存的大小

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

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

相关文章

正中优配:证券融资融券是什么意思?

证券融资融券&#xff08;简称“融资融券”&#xff09;是一种股票出资办法&#xff0c;是指出资者经过融券生意和融资生意来进行股票出资。它在出资商场上具有重要的作用&#xff0c;因为经过这种办法&#xff0c;出资者能够使用假贷资金进行股票生意&#xff0c;能够进步出资…

腾讯云4核8G服务器选CVM还是轻量比较好?价格对比

腾讯云4核8G云服务器可以选择轻量应用服务器或CVM云服务器标准型S5实例&#xff0c;轻量4核8G12M服务器446元一年&#xff0c;CVM S5云服务器935元一年&#xff0c;相对于云服务器CVM&#xff0c;轻量应用服务器性价比更高&#xff0c;轻量服务器CPU和CVM有区别吗&#xff1f;性…

23062C++QTday4

仿照string类&#xff0c;完成myString 类 代码&#xff1a; #include <iostream> #include <cstring> using namespace std; class myString {private:char *str; //记录c风格的字符串int size; //记录字符串的实际长度public://无参构造my…

华为云云耀云服务器L实例评测 | 由于自己原因导致MySQL数据库被攻击 【更新中。。。】

目录 引出起因&#xff08;si因&#xff09;解决报错诶嘿&#xff0c;连上了 不出意外&#xff0c;就出意外了打开数据库what&#xff1f;&#xff1f;&#xff1f; 找华为云求助教训&#xff1a;备份教训&#xff1a;密码 解决1.改密码2.新建一个MySQL&#xff0c;密码设置复杂…

Android T 窗口层级其三 —— 层级结构树添加窗口

文章目录 序节点添加Task以DefaultTaskDisplayArea为父节点以Task为父节点 ActivityRecordWindowTokenWindowState以WindowToken为父节点以ActivityRecord为父节点 小结调用场景添加差异 流程分析添加log堆栈打印流程LauncherStatusBar 序 尚未添加窗口的层级结构树&#xff0…

前端该了解的网络知识

网络 前端开发需要了解的网络知识 URL URL(uniform resource locator,统一资源定位符)用于定位网络服务. URL是一个固定格式的字符串 它表达了: 从网络中哪台计算机(domain)中的哪个服务(port),获取服务器上资源的路径(path),以及要用什么样的协议通信(schema). 注意: 当…

探索Netty的FuturePromise

Netty—Future&Promise 一、JDK原生 Future二、Netty包下的 Future三、Promise1、使用Promise同步获取结果2、使用Promise异步获取结果.3、使用Promise同步获取异常 - sync & get4、使用Promise同步获取异常 - await5、使用Promise异步获取异常 在异步处理时&#xff0…

颜色代码对照表

颜色代码对照表 各颜色代码: 1 白色 #FFFFFF 2 红色 #FF0000 3 绿色 #00FF00 4 蓝色 #0000FF 5 牡丹红 #FF00FF 6 青色 #00FFFF 7 黄色 #FFFF00 8 黑色 #000000 9 海蓝 #70DB93 …

出行类APP商业化路径解决方案

当下市场主流的商业化路径和方法相比于之前区别不大&#xff0c;开发者们都是在现有商业化体系下&#xff0c;制定更加详细、优质的策略&#xff0c;以期获得更高利益。 出行类App用户结构分析 年龄层次&#xff1a;出行类App用户的年龄分布比较广泛&#xff0c;主要集中在20…

商品防伪查询溯源小程序开发源码

企业商家在销售商品的过程中被人仿冒产品以次充好损害公司名声和影响产品销量是很多企业的痛点。我们基于次帮助企业开发了一款商品防伪溯源查询小程序&#xff0c;解决企业痛点&#xff0c;酿造更好的经商坏境。 核心功能&#xff1a; 我们采用一物一码的逻辑&#xff0c;可…

【网络基础】——HTTPS

目录 HTTPS背景知识 HTTPS是什么&#xff1f; 加密解密 为什么要加密 常见的加密方式 对称加密 非对称加密 数据摘要&&数据指纹 数字签名 HTTPS工作过程探究 方案1&#xff1a;只使用对称加密 方案2&#xff1a;只使用非对称加密 方案3&#xff1a;双方…

day37 线程

一、线程安全 二、多线程并发的安全问题 当多个线程并发操作同一临界资源 由于线程切换实际不确定 导致操作顺序出现混乱 产生的程序bug 严重时出现系统瘫痪 临界资源 &#xff1a;操作该资源的完整流程同一时间只能被单一线程操作的资源 多线程并发会出现的各种问题、 如…

IT运维:使用数据分析平台监控奇安信

监控目标 本文基于鸿鹄2.10.0版本。 ●监控奇安信日志类型分布 ●监控奇安信攻击行为、分析攻击类型 ●监控奇安信攻击来源情况 操作步骤 数据导入 1、创建数据集&#xff0c;如使用已经存在的数据集&#xff0c;可跳过此步骤 数据集名称&#xff1a;qax_syslog&#xff08;仪表…

管理类联考——数学——汇总篇——知识点突破——应用题——鸡兔同笼

⛲️ 一、考点讲解 第一鸡兔同笼问题 若已知脚数之和及鸡兔总数&#xff0c;求各多少只&#xff1a; 假设全都是鸡&#xff0c;则有 兔数 ( 实际脚数 − 2 鸡兔总数 ) ( 4 − 2 ) 兔数(实际脚数-2鸡兔总数)(4-2) 兔数(实际脚数−2鸡兔总数)(4−2) 假设全都是兔&#xff0…

Python 基础知识:语法、数据类型和控制结构

推荐&#xff1a;使用 NSDT场景编辑器 快速搭建3D应用场景 如果开发和环境中已安装 Python&#xff0c;请启动 Python REPL 和代码。或者&#xff0c;如果您想跳过安装并立即开始编码&#xff0c;我建议您前往Google Colab并一起编码。 你好&#xff0c;Python&#xff01; 在…

【算法日志】单调栈: 单调栈简介及其应用

代码随想录刷题60Day 目录 单调栈简介 单调栈的应用 下次更高温 下一个更大元素1 下一个更大元素2 接雨水 柱状图中最大矩形 单调栈简介 单调栈&#xff08;Monotonic Stack&#xff09;是一种特殊的栈数据结构&#xff0c;它满足元素的单调性&#xff0c;这种单调性需…

vue3使用el-form实现登录、注册功能,且进行表单验证(Element Plus中的el-form)

简介&#xff1a;Element Plus 中的 el-form 是一个表单组件&#xff0c;用于快速构建表单并进行数据校验。它提供了丰富的表单元素和验证规则&#xff0c;使表单开发变得更加简单和高效。可以搭配el-dialog实现当前页面的登录、注册页 &#xff0c;这两天在vue3中用到了表单登…

微信小程序 按钮颜色

<button type"primary">主要按钮样式类型</button> <button type"default">默认按钮样式类型</button> <button type"warn">警告按钮样式类型</button> <view>按钮plain是否镂空</view> <bu…

全局光照RSM

Reflective Shadow Maps&#xff08;RSM&#xff09; 一切被直接光照照到的物体&#xff0c;会作为次级光源。 问题1&#xff1a;哪些面片被直接照亮 使用ShadowMap就可以知道哪些面片被直接照亮 问题2&#xff1a;各个面片对P点的贡献分别是多少。 对渲染方程代入如上计算…

CRM客户管理系统能在线使用吗?

经常有朋友私信小编&#xff0c;mac系统/windows系统可以下载使用吗&#xff1f;在哪里下载&#xff1f;其实&#xff0c;Zoho CRM在线即可使用&#xff0c;完全不用下载客户端&#xff01;下面我们就说说&#xff0c;CRM管理系统如何在线用。 Zoho CRM是一款帮助企业进行客户…