Java算法之时间复杂度和空间复杂度的概念和计算

1. 算法效率

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

通常我们从时间效率和空间效率两个方面去分析算法的好坏。时间效率即时间复杂度,空间效率被称为空间复杂度。时间复杂度主要是衡量一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额外空间。

常见的复杂度大小比较:O(2^N) > O(N^2) > O(N*logN) > O(N) > O(logN) > O(1)

在计算机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。因为现在的内存不像以前那么贵,所以经常听到过牺牲空间来换取时间的说法

事后统计法

**这种方法可行,但不是一个好的方法。**该方法有两个缺陷:一是要想对设计的算法的运行性能进行评测,必须先依据算法编制相应的程序并实际运行;二是所得时间的统计量依赖于计算机的硬件、软件等环境因素,有时容易掩盖算法本身的优势。

事前分析估算的方法

因事后统计方法更多的依赖于计算机的硬件、软件等环境因素,有时容易掩盖算法本身的优劣。因此人们常常采用事前分析估算的方法
在编写程序前,依据统计方法对算法进行估算。一个程序在计算机上运行时所消耗的时间取决于下列因素:
(1) 算法采用的策略、方法;(2). 编译产生的代码质量;(3) 问题的输入规模;(4) 机器执行指令的速度。

2. 时间复杂度

定义:在计算机科学中,算法的时间复杂度是一个数学函数,它定量描述了该算法的运行时间。一个算法执行所耗费的时间与其中语句的执行次数成正比例,算法中基本的执行次数,即算法的时间复杂度。

通常在计算算法的时间复杂度时,并不一定要计算精确的执行次数,而只需要计算大概执行次数,我们通常使用大 O 渐进法来表示。

1. 用常数 1 来取代运行时间中所有的加法常数;

2. 只保留最高的阶项;

3. 如果最高项存在且不是 1,则去除与这个项目相乘的常数,得到的结果就是大 O 阶.

代码演示如下:

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

对于上述代码进行时间复杂度分析:

第一个嵌套 for 循环的执行次数为 N^2,第二个 for 循环的执行次数为 2N,第三个 while 循环的执行次数是 10, 则 F(N)=F(N^2) + F(2N)+10,根据大 O 渐进表示法,该算法的时间复杂度为 O(N^2).

算法的时间复杂度存在最好、平均、最坏情况:

最好情况:任意输入规模的最大运行次数(上界)

平均情况:任意输入规模的期望运行次数

最坏情况:任意输入规模的最小运行次数(下界)

注意: O(1) 表示基本语句的执行次数是一个常数,一般来说,只要算法中不存在循环语句,时间复杂度就为 O(1)。

下面选取一些常见的进行讲解

常数阶 O(1)

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

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

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

线性阶 O(n)

这个在最开始的代码示例中就讲解过了,如:

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

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

对数阶 O(logN)
int i = 1;
while(i<n)
{
    i = i * 2;
}

从上面代码可以看到,在 while 循环里面,每次都将 i 乘以 2,乘完之后,i 距离 n 就越来越近了。我们试着求解一下,假设循环 x 次之后,i 就大于 2 了,此时这个循环就退出了,也就是说 2 的 x 次方等于 n,那么 x = log2^n
也就是说当循环 log2^n 次以后,这个代码就结束了。因此这个代码的时间复杂度为:O(logn)

线性对数阶 O(nlogN)

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

就拿上面的代码加一点修改来举例:

for(m=1; m<n; m++)
{
    i = 1;
    while(i<n)
    {
        i = i * 2;
    }
}
平方阶 O(n2)

平方阶 O(n²) 就更容易理解了,如果把 O(n) 的代码再嵌套循环一遍,它的时间复杂度就是 O(n²) 了。
举例:

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

这段代码其实就是嵌套了 2 层 n 循环,它的时间复杂度就是 O(n*n),即 O(n²)
如果将其中一层循环的 n 改成 m,即:

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

那它的时间复杂度就变成了 O(m*n)

立方阶 O(n³)、K 次方阶 O(n^k)

参考上面的 O(n²) 去理解就好了,O(n³) 相当于三层 n 循环,其它的类似。

指数阶 O(2^N)

递归的时间复杂度计算: 递归的次数 * 每次递归后代码的执行次数 (也是用大 O 渐进法表示)

int Fibonacci(int N) 
{
    return N < 2 ? N : Fibonacci(N-1)+Fibonacci(N-2);
}

上面的代码是一个计算斐波那契数列的方法,使用的是递归的方法,我们知道递归的方法来计算斐波那契数列是非常低效的,最好还是使用循环的方法,但是递归的时间复杂度是多少呢?
我们知道每一次调用这个方法时,我们的时间复杂度是一个常数,那么这个递归的时间复杂度就是我们一共调用了多少次方法,现在我们来分析一下我们到底调用了多少次这个方法。
其调用结构如图所示

在这里插入图片描述

当我们输入 N 时,方法会进行两调用,然后不断地调用,其调用的结果如图所示,在右下角是有一个空缺区域的,但是我们可以把这一块空缺的区域看作一个常数,假设它是满的,那么我们执行调用的总次数为 F(N)=2⁰+2¹+2²+…+2N-1=2N-1(使用等比数列得出结果),所以该算法的时间按复杂度为 O(2^N)。
由以上的计算我们就可以发现用递归来算斐波那契数的算法的时间复杂度太高了,也就说明了这个算法的低效。

除此之外,其实还有 平均时间复杂度、均摊时间复杂度、最坏时间复杂度、最好时间复杂度 的分析方法,有点复杂,这里就不展开了。

3. 空间复杂度

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

注意:函数运行时所需要的栈空间 (存储参数、局部变量、一些寄存器信息等) 在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。

1. 一个算法在计算机上占用的内存包括:程序代码所占用的空间,输入输出数据所占用的空间,辅助变量所占用的空间这三个方面,程序代码所占用的空间取决于算法本身的长短,输入输出数据所占用的空间取决于要解决的问题,是通过参数表调用函数传递而来,只有辅助变量是算法运行过程中临时占用的存储空间,与空间复杂度相关;

2. 通常来说,只要算法不涉及到动态分配的空间,以及递归、栈所需的空间,空间复杂度通常为 O(1);

代码演示如下:

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;
}

空间复杂度:O(1)

这里需要理解:算法在运行过程中临时占用存储空间(额外)大小的量度,这里这开辟 end,sorted ,i 三个零时变量,因为大 O 渐进表示法,3 为常数所以为 1 。

空间复杂度 O(n)

int[] m = new int[n]
for(i=1; i<=n; ++i)
{
   j = i;
   j++;
}

这段代码中,第一行 new 了一个数组出来,这个数据占用的大小为 n,这段代码的 2-6 行,虽然有循环,但没有再分配新的空间,因此,这段代码的空间复杂度主要看第一行即可,即 O(n)

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

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

相关文章

业务与数据的终极对决:如何让大数据成为企业的超能力?

在数字化转型的浪潮中&#xff0c;企业如同在茫茫数据海洋中航行的船只&#xff0c;而数据资产管理就是指引航向的罗盘。但是&#xff0c;当业务需求与数据脱节、数据孤岛林立、业务流程与数据流程不同步、以及业务增长带来的数据管理挑战成为阻碍&#xff0c;我们该如何突破重…

transformer上手(7)—— 快速分词器

1 快速分词器 Hugging Face 共提供了两种分分词器&#xff1a; 慢速分词器&#xff1a;Transformers 库自带&#xff0c;使用 Python 编写&#xff1b;快速分词器&#xff1a;Tokenizers 库提供&#xff0c;使用 Rust 编写。 特别地&#xff0c;快速分词器除了能进行编码和解…

单链表链表专题

1 链表的概念 概念&#xff1a;链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 链表的结构跟⽕⻋⻋厢相似&#xff0c;淡季时⻋次的⻋厢会相应减少&#xff0c;旺季时⻋次的⻋厢会额外增加⼏节。只 需要…

Redis实现延迟任务的几种方案

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 目录 1.前言 2.Redis如何实现延迟任务&#xff1f; 3.代码实现 3.1. 过期键通知事…

技术速递|为 .NET iOS 和 .NET MAUI 应用程序添加 Apple 隐私清单支持

作者&#xff1a;Gerald Versluis 排版&#xff1a;Alan Wang Apple 正在推出一项隐私政策&#xff0c;将隐私清单文件包含在针对 App Store 上的 iOS、iPadOS 和 tvOS 平台的新应用程序和更新应用程序中。请注意&#xff0c;至少目前 macOS 应用程序被排除在外。 隐私清单文件…

这部经典之作,时隔六年迎来重磅升级!

&#x1f345; 作者简介&#xff1a;哪吒&#xff0c;CSDN2021博客之星亚军&#x1f3c6;、新星计划导师✌、博客专家&#x1f4aa; &#x1f345; 哪吒多年工作总结&#xff1a;Java学习路线总结&#xff0c;搬砖工逆袭Java架构师 &#x1f345; 技术交流&#xff1a;定期更新…

Niobe WiFi IoT开发板OpenHarmony内核编程开发——Semaphore

本示例将演示如何在Niobe WiFi IoT开发板上使用cmsis 2.0 接口进行信号量开发 Semaphore API分析 osThreadNew() osThreadId_t osThreadNew(osThreadFunc_t func, void *argument,const osThreadAttr_t *attr )描述&#xff1a; 函数osThreadNew通过将线程添加到活动线程列表…

TG-12F使用SDK对接阿里生活物联网平台

文章目录 前言一、注意二、准备1. 安装Ubuntu&#xff08;版本20.04 X64&#xff09;程序运行时库。按顺序逐条执行命令&#xff1a;2. 安装Ubuntu&#xff08;版本20.04 X64&#xff09;依赖软件包。按照顺序逐条执行命令&#xff1a;3. 安装Python依赖包。按照顺序逐条执行命…

vscode 打代码光标特效

vscode 打代码光标特效 在设置里面找到settings 进入之后在代码最下方加入此代码 "explorer.confirmDelete": false,"powermode.enabled": true, //启动"powermode.presets": "fireworks", // 火花效果// particles、 simple-rift、e…

FFmpeg: 自实现ijkplayer播放器--04消息队列设计

文章目录 播放器状态转换图播放器状态对应的消息&#xff1a; 消息对象消息队列消息队列api插入消息获取消息初始化消息插入消息加锁初始化消息设置消息参数消息队列初始化清空消息销毁消息启动消息队列终止消息队列删除消息 消息队列&#xff0c;用于发送&#xff0c;设置播放…

eclipse导入maven项目与配置使用本地仓库

前言 本人润国外了&#xff0c;发现不能用收费软件IDEA了&#xff0c;需要使用eclipse&#xff0c;这个免费。 但是早忘了怎么用了&#xff0c;在此总结下。 一、eclipse导入本地项目 1.选这个&#xff1a;open projects from file system… 2.找到项目文件夹&#xff0c;…

如何编写易于访问的技术文档 - 最佳实践与示例

当你为项目或工具编写技术文档时&#xff0c;你会希望它易于访问。这意味着它将为全球网络上的多样化受众提供服务并可用。 网络无障碍旨在使任何人都能访问网络内容。设计师、开发人员和撰写人员有共同的无障碍最佳实践。本文将涵盖一些创建技术内容的最佳实践。 &#xff0…

KIVY 学习1

环境 python 3.6 3.7 对应Kivy 1.11.1版本各依赖 python -m pip install docutils pygments pypiwin32 kivy_deps.sdl20.1.22 kivy_deps.glew0.1.12 这是一个用于安装Python包的命令&#xff0c;它会安装一些特定的包。具体来说&#xff0c;这个命令会安装以下包&#xff1a; …

Python的国际化和本地化【第162篇—国际化和本地化】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 随着全球化的发展&#xff0c;多语言支持在软件开发中变得越来越重要。Python作为一种流行的…

Springboot+Vue项目-基于Java+Mysql的网上订餐系统(附源码+LW+演示录像)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

游戏实践:扫雷

一.游戏介绍 虽然很多人玩过这个游戏&#xff0c;但还是介绍一下。在下面的格子里&#xff0c;埋的有10颗雷&#xff0c;我们通过鼠标点击的方式&#xff0c;点出你认为不是雷的地方&#xff0c;等到把所有没有雷的格子点完之后&#xff0c;及视为游戏胜利。 上面的数字的意思…

Linux第90步_异步通知实验

“异步通知”的核心就是信号&#xff0c;由“驱动设备”主动报告给“应用程序”的。 1、添加“EXTI3.c” #include "EXTI3.h" #include <linux/gpio.h> //使能gpio_request(),gpio_free(),gpio_direction_input(), //使能gpio_direction_output(),gpio_get_v…

数据资产管理制度探索——浙江篇

在行政事业单位数据资产管理领域&#xff0c;浙江省以创新性思维与高质量发展的战略眼光&#xff0c;积极探索并构建了具有前瞻性和实效性的数据资产管理制度。作为财政部数据资产管理试点省份&#xff0c;浙江省财政厅与省标准化研究院强强联合&#xff0c;充分运用数据溯源、…

40.原子累加器

java8之后&#xff0c;新增了专门用于计数的类&#xff0c;LongAccumulator,LongAdder的性能高于AtomicLong。 LongAdder 性能 > AtomicLong 性能 性能高的原因&#xff1a;如果都往一个共享变量上面进行累加&#xff0c;那么比较重试的次数肯定就多&#xff1b;如果分成几…

KubeSphere中间件部署

中间件部署实战 语雀 RuoYi-Cloud部署实战 语雀 https://www.bilibili.com/video/BV13Q4y1C7hS?p79 应用部署三要素 应用的部署方式&#xff08;Deployment、StatefulSet、DaemonSet&#xff09; 应用的数据挂载&#xff08;数据、配置文件&#xff09; 应用的可访问性…