复杂度分析之大O表示法。

2024-02-08 02:18

本文主要是介绍复杂度分析之大O表示法。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、概要。
好的程序设计表现出程序执行速度快,占用内存空间小的优点,分别对应时间复杂度和空间复杂度。
2、复杂度分类两种。
算法的时间复杂度是指算法需要消耗的时间资源。算法执行时间的增长率与f(n) 的增长率正相关,称作渐近时间复杂度(Asymptotic Time Complexity),简称时间复杂度。定义为T(n) = O(f(n)),称函数T(n)以f(n)为界或者称T(n)受限于f(n)。
算法的空间复杂度是指算法需要消耗的空间资源。其计算和表示方法与时间复杂度类似,一般都用复杂度的渐近性来表示。

常见的算法时间复杂度由小到大依次为:
O(1) 常数阶
O(logn) 对数阶
O(n) 线性阶
O(n*logn) 线性对数阶
O(n^2) 平方阶
O(n^k) K方阶
O(2^n) 指数阶
O(n!) 阶乘阶

其中,O(2^n) 和O(n!)为非多项式量级,NP(Non-Deterministic Polynomial,非确定多项式)问题,其复杂度计算机往往不能承受的。除此二者,都是多项式量级。
在这里插入图片描述
图表来源:https://www.bigocheatsheet.com

3、时间复杂度。
3.1辨识要素及示例。

int CalcSum(int n)
{int sum = 0;for (int i = 0; i < n; i++){sum += i;}return sum;
}

Demo求累加和,假设每条语句执行时间为time,容易算出来该函数运行时间为:T(n) = time+time+ntime2 = 2*(n+1)*time。用f(n)来表示代码的执行次数和数据规模的关系,即f(n)=2n+2。f(n)中的常数项对于整个公式的值的影响我们直接忽略,同样,我们也忽略系数。即得:f(n) = n;代入T(n) = O(f(n)),得:T(n) = O(n),线性阶。

①、只关注循环执行次数最多的一段代码;


int CalcSum(int n)
{int sum1 = 0;int sum2 = 0;for (int i = 0; i < n; i++){sum1 += i;}for (int j = 0; j < n * 2; j++){sum2 += j;}return sum1 + sum2;
}

容易看出来循环二比循环一的执行次数多,因此只需要关注循环二,得到T(n) = O(n);线性阶。
②、加法法则:总复杂度等于量级最大的那段代码的复杂度;

int CalcSum(int n)
{int sum1 = 0;int sum2 = 0;int sum3 = 0;for (int i = 0; i < 100; i++){sum1 += i;}for (int j = 0; j < n; j++){sum2 += j;}for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){sum3 += j;}}return sum1 + sum2 + sum3;
}

容易得到循环一二三的时间复杂度分别为:O(1) (常数阶),O(n)(线性阶),O(n^2)(平方阶);则T(n) = O(1)+O(n)+O(n^2);按照加法原则,总复杂度等于量级最大的那段代码的复杂度。即T(n) = O(n^2),平方阶。
③、乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积。


int CalcSum(int n)
{int sum = 0;for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){sum += j;}}return sum;
}

嵌套循环 = 外层内层。即T(n) = O(nn) = O(n^2),平方阶。
Ps:
对数阶:

int CalcSum(int n)
{int sum = 0;int i = 1;do{i = i * 2;sum += i;} while (i < n);return sum;
}

在while循环里面,每次都将 i 乘以 2翻倍,距离n越来越近。循环x次后,退出,也就是说2^x >=n。那么x = log2n(以2为底,n的对数)。这就是对数阶,时间复杂度为:T(n) = O(logn)。
线性对数阶:
将对数阶循环n遍,就是线性对数阶。即:T(n) = n*(O(logn)) = O(n*logn)。
3.2时间复杂度三种类别。
时间复杂度里细分起来又有最好、最坏、平均情况时间复杂度之分:
1、最好情况时间复杂度就是在最理想的情况下,执行这段代码的时间复杂度;
2、最坏情况时间复杂度就是在最糟糕的情况下,执行这段代码的时间复杂度;
3、平均情况时间复杂度顾名思义就是结合概率论分析从最好到最坏每种情况平均下来的加权平均时间复杂度。
在这里插入图片描述
图表来源:https://www.bigocheatsheet.com
4、空间复杂度。
空间复杂度比较常用的有:O(1)、O(n)、O(n²)。
4.1 S(n) = O(1).
不存在存储空间随变量变化情况。

void GetSpace(int n)
{vector<int> array;array.push_back(1);array.push_back(2);array.push_back(3);array.push_back(4);array.push_back(5);int sum = 0;for (auto it:array){sum += it;}
}

4.2 S(n) = O(n).
例程中,申请空间后,没有在申请其他空间。复杂度为:O(n)。

void GetSpace(int n)
{int* p = new int[n];int sum = 0;for (int i = 0; i <= n; ++i){sum += i;}
}

5、 总结
①、算法的速度并非指时间,不是以秒为单位;而是操作数的增速。从增量的角度度量的。
②、平时说算法的速度,指的是随着输入的增加,其运行时间将会以什么样的速度进行增加。
③、算法运行时间用大O表示法表示。
④、 O(㏒n)比O(n)快。当操作的元素规模差距越大,快的越明显。

这篇关于复杂度分析之大O表示法。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/689640

相关文章

[职场] 公务员的利弊分析 #知识分享#经验分享#其他

公务员的利弊分析     公务员作为一种稳定的职业选择,一直备受人们的关注。然而,就像任何其他职业一样,公务员职位也有其利与弊。本文将对公务员的利弊进行分析,帮助读者更好地了解这一职业的特点。 利: 1. 稳定的职业:公务员职位通常具有较高的稳定性,一旦进入公务员队伍,往往可以享受到稳定的工作环境和薪资待遇。这对于那些追求稳定的人来说,是一个很大的优势。 2. 薪资福利优厚:公务员的薪资和

高度内卷下,企业如何通过VOC(客户之声)做好竞争分析?

VOC,即客户之声,是一种通过收集和分析客户反馈、需求和期望,来洞察市场趋势和竞争对手动态的方法。在高度内卷的市场环境下,VOC不仅能够帮助企业了解客户的真实需求,还能为企业提供宝贵的竞争情报,助力企业在竞争中占据有利地位。 那么,企业该如何通过VOC(客户之声)做好竞争分析呢?深圳天行健企业管理咨询公司解析如下: 首先,要建立完善的VOC收集机制。这包括通过线上渠道(如社交媒体、官网留言

打包体积分析和优化

webpack分析工具:webpack-bundle-analyzer 1. 通过<script src="./vue.js"></script>方式引入vue、vuex、vue-router等包(CDN) // webpack.config.jsif(process.env.NODE_ENV==='production') {module.exports = {devtool: 'none

Java中的大数据处理与分析架构

Java中的大数据处理与分析架构 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们来讨论Java中的大数据处理与分析架构。随着大数据时代的到来,海量数据的存储、处理和分析变得至关重要。Java作为一门广泛使用的编程语言,在大数据领域有着广泛的应用。本文将介绍Java在大数据处理和分析中的关键技术和架构设计。 大数据处理与

段,页,段页,三种内存(RAM)管理机制分析

段,页,段页         是为实现虚拟内存而产生的技术。直接使用物理内存弊端:地址空间不隔离,内存使用效率低。 段 段:就是按照二进制文件的格式,在内存给进程分段(包括堆栈、数据段、代码段)。通过段寄存器中的段表来进行虚拟地址和物理地址的转换。 段实现的虚拟地址 = 段号+offset 物理地址:被分为很多个有编号的段,每个进程的虚拟地址都有段号,这样可以实现虚实地址之间的转换。其实所谓的地

mediasoup 源码分析 (八)分析PlainTransport

mediasoup 源码分析 (六)分析PlainTransport 一、接收裸RTP流二、mediasoup 中udp建立过程 tips 一、接收裸RTP流 PlainTransport 可以接收裸RTP流,也可以接收AES加密的RTP流。源码中提供了一个通过ffmpeg发送裸RTP流到mediasoup的脚本,具体地址为:mediasoup-demo/broadcaste

Java并发编程—阻塞队列源码分析

在前面几篇文章中,我们讨论了同步容器(Hashtable、Vector),也讨论了并发容器(ConcurrentHashMap、CopyOnWriteArrayList),这些工具都为我们编写多线程程序提供了很大的方便。今天我们来讨论另外一类容器:阻塞队列。   在前面我们接触的队列都是非阻塞队列,比如PriorityQueue、LinkedList(LinkedList是双向链表,它实现了D

线程池ThreadPoolExecutor类源码分析

Java并发编程:线程池的使用   在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:   如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。   那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?

ConcurrentHashMap之源码分析

集合是编程中最常用的数据结构。而谈到并发,几乎总是离不开集合这类高级数据结构的支持。比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap)。这篇文章主要分析jdk1.5的3种并发集合类型(concurrent,copyonright,queue)中的ConcurrentHashMap,让我们从原理上细致的了解它们,能够让我们在深度项目开发中获益非浅

Hashtable的源码分析

Hashtable简介     Hashtable同样是基于哈希表实现的,同样每个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长。     Hashtable也是JDK1.0引入的类,是线程安全的,能用于多线程环境中。     Hashtable同样实现了Serializable接口,它支持序列化,实现了Cloneable接