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

空间复杂度和时间复杂度

文章目录

  • 空间复杂度和时间复杂度
    • 空间复杂度
    • 时间复杂度
      • **评价排序算法**
      • **时间频度**
        • **什么是时间频度**
        • **忽略常数项**
        • **忽略低次项**
        • **忽略系数**
      • **时间复杂度**
        • **什么是时间复杂度**
        • **计算时间复杂度的方法**
        • **常见的时间复杂度**
      • **常见的时间复杂度**
        • **常数阶**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.rhkb.cn/news/129681.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Weblogic(CVE-2017-10271)与 Struts2(s2-045) 反序列化漏洞复现

文章目录 Java 反序列化漏洞复现weblogic环境搭建漏洞复现 Struts2(s2-045)环境搭建漏洞复现**漏洞利用** Java 反序列化漏洞复现 weblogic Weblogic < 10.3.6 ‘wls-wsat’ XMLDecoder 反序列化漏洞&#xff08;CVE-2017-10271&#xff09; ​ Weblogic的WLS Security组…

【ARM CoreLink 系列 2 -- CCI-400 控制器简介】

文章目录 CCI-400 介绍DVM 机制介绍DVM 消息传输过程TOKEN 机制介绍 下篇文章&#xff1a;ARM CoreLink 系列 3 – CCI-550 控制器介绍 CCI-400 介绍 CCI&#xff08;Cache Coherent Interconnect&#xff09;是ARM 中 的Cache一致性控制器。 CCI-400 将 Interconnect 和coh…

SUMPRODUCT函数

SUMPRODUCT函数返回相应范围或数组的个数之和。 默认操作是乘法&#xff0c;但也可以执行加减除运算。 本示例使用 SUMPRODUCT 返回给定项和大小的总销售额&#xff1a; SUMPRODUCT 匹配项 Y/大小 M 的所有实例并求和&#xff0c;因此对于此示例&#xff0c;21 加 41 等于 62。…

pytorch中的词性标注_seq2seq_比较naive的示例

一、各种用法_查漏补缺&#xff1a; 1.关于numpy中的argmax的用法&#xff1a; numpy之argmax()函数 - 知乎 (zhihu.com) 具体看这篇文章够了 二、代码注释&#xff1a; 参考&#xff1a; Sequence Models and Long Short-Term Memory Networks — PyTorch Tutorials 2.0.…

【1++的数据结构】之map与set(二)

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的数据结构】 文章目录 一&#xff0c;前言二&#xff0c;红黑树的概念及其性质三&#xff0c;红黑树的插入四&#xff0c;红黑树的验证五&#xff0c;map与set的封装红黑树迭代器的实现map重载…

qt 正则表达式

以上是正则表达式的格式说明 以下是自己写的正则表达式 22-25行 是一种设置正则表达式的方式&#xff0c; 29-34行 : 29行 new一个正则表达式的过滤器对象 30行 正则表达式 的过滤格式 这个格式是0-321的任意数字都可以输入 31行 将过滤格式保存到过滤器对象里面 32行 将验…

快人一步进入智能新纪元,《新程序员006》来了!

文 | 王启隆 曾浩辰 出品 | 《新程序员》编辑部 亲爱的 CSDN 以及《新程序员》的读者朋友们&#xff0c;金秋将至&#xff0c;《新程序员006&#xff1a;人工智能新十年》也正式与大家见面&#xff01;现在点击下方封面&#xff0c;即可订阅&#xff0c;立即阅读电子书。精美…

UNIX网络编程卷一 学习笔记 第三十章 客户/服务器程序设计范式

开发一个Unix服务器程序时&#xff0c;我们本书做过的进程控制&#xff1a; 1.迭代服务器&#xff08;iterative server&#xff09;&#xff0c;它的适用情形极为有限&#xff0c;因为这样的服务器在完成对当前客户的服务前无法处理已等待服务的新客户。 2.并发服务器&#x…

Java笔记040-反射/反射机制、Class类

目录 反射(reflection) 一个需求引出反射 反射机制 Java反射机制原理图 Java反射机制可以完成 反射相关的主要类 反射机制的优点和缺点 反射调用优化-关闭访问检查 Class类 基本介绍 代码解释部分 类加载方法 应用实例&#xff1a;Class02.java 获取Class类对象 …

【17 > 分布式接口幂等性】2. Update的幂等性原理解析

一、 根据 唯一业务号去更新 数据的情况 1.1 原理 1.2 操作 1.3 实战 Stage 1&#xff1a;表添加 version 字段 Stage 2&#xff1a;前端 > 版本号放入隐藏域 Stage 3&#xff1a;后台 > 使用版本号作为更新条件 二、更新操作没有唯一业务号&#xff0c;可使用Tok…

RP9学习-1

一.基础 1.10个面板位置示意图&#xff1a; 2.常用英文 1.鼠标点击&#xff1a;click or tap 3.工作区 1.恢复默认工作区&#xff1a; view-->reset view 2.自定义工作区&#xff1a; 可以用鼠标左键拖动面板到独立的位置或者吸附到其他面板上 3.自定义工具栏 view-->T…

Adobe Acrobat Reader界面改版 - 解决方案

问题 日期&#xff1a;2023年9月 Adobe Acrobat Reader下文简称Adobe PDF Reader&#xff0c;此软件会自动进行更新&#xff0c;当版本更新至2023.003.20284版本后。 软件UI界面会大改版&#xff1a;书签页变成了右边、工具栏变到了左边、缩放按钮变到了右下角&#xff0c;如…

打造高效的私密论坛网站:Cpolar内网穿透+HadSky轻量级搭建指南

文章目录 前言1. 网站搭建1.1 网页下载和安装1.2 网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3 Cpolar稳定隧道&#xff08;本地设置&#xff09;2.4 公网访问测试 总结 前言 经过多年的基础…

怎么激活IDM

IDM是一个下载软件。 激活它需要用到git上面的一个项目&#xff0c;同时网络要能连到github GitHub - lstprjct/IDM-Activation-Script: IDM Activation & Trail Reset Script WINR 输入powershell 输入命令行 iex(irm is.gd/idm_reset) 或者 iwr -useb https://raw.…

vim常用操作

一、Esc键 & 命令模式 1.撤销&#xff1a;u 恢复撤销&#xff1a;Ctrl r 2.定位 行首&#xff1a;0 行尾&#xff1a;$ 第7行&#xff1a;7G 3.编辑 下行开始插入&#xff1a; o 删除行&#xff1a;dd 复制3行并粘贴&#xff1a;3yy ---> p 复制单词并粘贴&#…

【Leetcode-面试经典150题-day22】

目录 97. 交错字符串 97. 交错字符串 题意&#xff1a; 给定三个字符串 s1、s2、s3&#xff0c;请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。 两个字符串 s 和 t 交错 的定义与过程如下&#xff0c;其中每个字符串都会被分割成若干 非空 子字符串&#xff1a; s s1 s2 …

Hadoop:HDFS--分布式文件存储系统

目录 HDFS的基础架构 VMware虚拟机部署HDFS集群 HDFS集群启停命令 HDFS Shell操作 hadoop 命令体系&#xff1a; 创建文件夹 -mkdir 查看目录内容 -ls 上传文件到hdfs -put 查看HDFS文件内容 -cat 下载HDFS文件 -get 复制HDFS文件 -cp 追加数据到HDFS文件中 -appendTo…

初阶扫雷(超详解)

✨博客主页&#xff1a;小钱编程成长记 &#x1f388;博客专栏&#xff1a;C语言小游戏 &#x1f388;推荐相关博文&#xff1a;初阶三子棋&#xff08;超详解&#xff09; 初阶扫雷 1.游戏介绍2.基本思路3.实现前的准备4.实现步骤4.1 打印菜单4.2 初始化扫雷棋盘4.3 打印扫雷棋…

如何让Android平台像网络摄像机一样实现GB28181前端设备接入?

技术背景 好多开发者在做国标对接的时候&#xff0c;首先想到的是IPC&#xff08;网络摄像头&#xff09;&#xff0c;通过参数化配置&#xff0c;接入到国标平台&#xff0c;实现媒体数据的按需查看等操作。 像执法记录仪等智能终端&#xff0c;跑在Android平台&#xff0c;…

2024腾讯校招后端面试真题汇总及其解答(三)

21【算法题】反转链表 题目: 给定单链表的头节点 head ,请反转链表,并返回反转后的链表的头节点。 示例 1: 输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]示例 2: 输入:head = [1,2] 输出:[2,1]示例 3: 输入:head = [] 输出:[]提示: 链表中节点的数目范围是 [0, 5…