【时间复杂度和空间复杂度】

news2024/10/7 14:34:13

1.时间复杂度

时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个数学函数,它定量描述了该算法的额外运行时间。一个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才知道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度个分析方式。一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为法的时间复杂度。

即:找到某条基本语句与问题规模N之间的数学表达式,就是算出了该算法的时间复杂度。

总的来说,时间复杂度就是大致计算代码运行的次数。

举一些例子分析:

1.嵌套的时间复杂度计算

// 请计算一下Func1中++count语句总共执行了多少次?
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--)
{
++count;
}
printf("%d\n",count);
}

实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这

里我们使用大O的渐进表示法。

推导大O阶方法:

1、用常数1取代运行时间中的所有加法常数。

2、在修改后的运行次数函数中,只保留最高阶项。

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

使用大O的渐进表示法以后,Func1的时间复杂度为:O(N^2)。

总的来说,1.就是使用O(1)来代表常数量级的运行次数

2.如果一段代码的运行次数是F(N) = N + 2,那么就保留最高阶项,时间复杂度为O(N)。

3.如果一段代码的运行次数是F(N) = 2*N^2,那么就去掉系数,时间复杂度为O(N^2)。

通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。

另外有些算法的时间复杂度存在最好、平均和最坏情况:

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

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

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

例如:在一个长度为N数组中搜索一个数据x

最好情况:1次找到

最坏情况:N次找到

平均情况:N/2次找到

在实际中一般情况关注的是算法的最坏运行情况,所以数组中搜索数据时间复杂度为O(N)。

常见的时间复杂度计算:

  1. 双重循环时间复杂度计算

// 计算Func2的时间复杂度?
void Func2(int N)
{
int count = 0;
for (int k = 0; k < 2 * N ; ++ k)
{
++count;
}
int M = 10;
while (M--)
{
++count;
}
printf("%d\n", count);
}

可以看出,运行次数为F(N) = 2*N +10 , 根据大O的表示法,时间复杂度为O(N)。

// 计算Func3的时间复杂度?
void Func3(int N, int M)
{
int count = 0;
for (int k = 0; k < M; ++ k)
{
++count;
}
for (int k = 0; k < N ; ++ k)
{
++count;
}
printf("%d\n", count);
}

先计算运行次数为F(N) = M*N,那么时间复杂度为O(N)或者O(M),取决于M和N的大小:

  1. 当M>>N 时,时间复杂度为O(M)

  1. 当N>>M 时,时间复杂度为O(N)

  1. 当M和N差不多大时,时间复杂度为O(M)或者O(N)

2.常数循环的时间复杂度

// 计算Func4的时间复杂度?
void Func4(int N)
{
int count = 0;
for (int k = 0; k < 100; ++ k)
{
++count;
}
printf("%d\n", count);
}

运行次数为F(N) = 100,所以时间复杂度为O(1).

注意:时间复杂度为O(1)并不代码代码只循环一次,而是常数次。

  1. strchar的时间复杂度。

strchar是从一个长度为N的字符串中查找一个字符的函数。

该函数的核心部分如上,假设从hello world中查找。

所以做悲观预期,时间复杂度为O(N)。

5.冒泡排序时间复杂度

// 计算BubbleSort的时间复杂度?
void BubbleSort(int* a, int n)
{
assert(a);
for (size_t end = n; end > 0; --end)
{
int exchange = 0;
for (size_t i = 1; i < end; ++i)
{
if (a[i-1] > a[i])
{
Swap(&a[i-1], &a[i]);
exchange = 1;
}
}
if (exchange == 0)
break;
}
}

对于一个冒泡排序,假设有10个数需要排序,第一次要排9次,第二次排8次,第三次排7次...

假设有n个数要排序,第一次排n-1次,第二次排n-2次,第三次排n-3次...

直到排到剩下一个数,就不需要排序了。

所以运行次数为F(N) = (N-1) +(N-2) + (N-3) +...+1,这是一个等差数列求和,所以可以认为,运行次数为F(N) = (N-1)*N/2,所以时间复杂度为O(N^2)。

6.二分查找的时间复杂度

// 计算BinarySearch的时间复杂度?
int BinarySearch(int* a, int n, int x)
{
assert(a);
int begin = 0;
int end = n-1;
while (begin < end)
{
int mid = begin + ((end-begin)>>1);
if (a[mid] < x)
begin = mid+1;
else if (a[mid] > x)
end = mid;
else
return mid;
}
return -1;

求时间复杂度不能只看循环的次数,需要结合算法的实际来看。

假设有100个数字,查找最坏的情况,查找一次,除以2,查找一次,除以2,最后,就只剩下一个数字。 也就是 100/2/2/2/2/2/2 =1 。 所以查找次数7次。

假设有n个数字,要查找x次才到1,那么就是 2^x = n , 所以x = log以2为底n的对数。

所以二分查找的时间复杂度为O(log以2为底n的对数)

7.递归算法的时间复杂度

计算方法:递归次数*每次递归调用的次数

  1. 阶乘递归时间复杂度

// 计算阶乘递归Fac的时间复杂度?
long long Fac(size_t N)
{
if(0 == N)
return 1;
return Fac(N-1)*N;
}

递归次数为N-1,每次调用一次,所以时间复杂度为O(N)。

2.斐波那契数列时间复杂度

// 计算斐波那契递归Fib的时间复杂度?
long long Fib(size_t N)
{
if(N < 3)
return 1;
return Fib(N-1) + Fib(N-2);
}

画出斐波那契的计算图:

计算次数是 2^0* 2^1* 2^2* ...* 2^N-2* 2^N-1 - X,这是一个等比数列,F(N) =2^N -1 -X ,

时间复杂度为O(2^N)。

2.空间复杂度

空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用存储空间大小的量度 。

空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。

空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法。

注意:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,因

此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。

总的来说,空间复杂度是计算变量个数的。

1.计算冒泡排序的空间复杂度

// 计算BubbleSort的空间复杂度?
void BubbleSort(int* a, int n)
{
assert(a);
for (size_t end = n; end > 0; --end)
{
int exchange = 0;
for (size_t i = 1; i < end; ++i)
{
if (a[i-1] > a[i])
{
Swap(&a[i-1], &a[i]);
exchange = 1;
}
}
if (exchange == 0)
break;
}
}

对一个冒泡排序来说,空间复杂度是看该排序中的变量的个数,在外部循环中,创建了一个变量n,内部循环创建了一个变量i,但是,在出了内部循环后,i就销毁了, 再次进去才又创建了变量i,重新创建的变量i是占用之前创建的变量的空间的。 同理,exchange变量也是如此,总体来说,程序相当于只创建了3个变量,所以空间复杂度为O(1).

2.计算斐波那契额数列的空间复杂度

// 计算Fibonacci的空间复杂度?
// 返回斐波那契数列的前n项
long long* Fibonacci(size_t n)
{
if(n==0)
return NULL;
long long * fibArray = (long long *)malloc((n+1) * sizeof(long long));
fibArray[0] = 0;
fibArray[1] = 1;
for (int i = 2; i <= n ; ++i)
{
fibArray[i] = fibArray[i - 1] + fibArray [i - 2];
}
return fibArray;
}

对于变量的创建和销毁来说,先创建Fib(N),再有Fib(N-1),再有Fib(N-2),一直往下走,最后创建Fib(2),Fib(1)。随后销毁之前创建的N个变量,再去创建Fib(N-1),到Fib(N-3),一直往下走,之后每一次创建的变量均小于第一次创建的N个变量个数,所以空间复杂度是O(N).

3.阶乘递归的空间复杂度:

// 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{
if(N == 0)
return 1;
return Fac(N-1)*N;
}

与斐波那契额数列同理,阶乘递归的空间复杂度是O(N).

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

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

相关文章

Linux系统用户和权限

文章目录root用户用户、用户组管理查看权限控制修改权限控制 - chmod修改权限控制 - chownroot用户 无论是Windows、MacOS、Linux均采用多用户的管理模式进行权限管理。 在Linux系统中&#xff0c;拥有最大权限的账户名为&#xff1a;root&#xff08;超级管理员&#xff09; …

机器学习(七):Azure机器学习模型搭建实验

文章目录 Azure机器学习模型搭建实验 前言 Azure平台简介 Azure机器学习实验 Azure机器学习模型搭建实验 前言 了解Azure机器学习平台&#xff0c;知道机器学习流程。 Azure平台简介 Azure Machine Learning&#xff08;简称“AML”&#xff09;是微软在其公有云Azure上推…

前缀树 字典树 TrieTree的学习与模拟实现

目录前言前缀树介绍C实现核心思想前缀树的大致框架前缀树插入字符串前缀树查找完整的字符串前缀树查找前缀匹配的字符串前缀树删除完整字符串总结完整代码前言 哥们在去年12月的一次实习面试的时候&#xff0c;远在旧金山的一家美企CTO面试我&#xff0c;岗位在西安&#xff0…

【MySQL进阶】MySQL视图详解

序号系列文章6【MySQL基础】MySQL单表操作详解7【MySQL基础】运算符及相关函数详解8【MySQL基础】MySQL多表操作详解9【MySQL进阶】MySQL事务详解文章目录前言1&#xff0c;视图1.1&#xff0c;视图概述1.2&#xff0c;视图使用环境1.3&#xff0c;视图创建格式1.4&#xff0c;…

【C语言课堂】 函数递归

欢迎来到 Claffic 的博客 &#x1f49e;&#x1f49e;&#x1f49e; 前言&#xff1a; 时隔多日&#xff0c;来还欠大家的 C 语言学习啦&#xff0c;上期讲了函数&#xff0c;其实函数中应该包括函数递归的&#xff0c;这里单独拿出来讲解的原因是函数递归属于重难知识&#xf…

【编程入门】开源记事本(Flutter版)

背景 前面已输出多个系列&#xff1a; 《十余种编程语言做个计算器》 《十余种编程语言写2048小游戏》 《17种编程语言10种排序算法》 《十余种编程语言写博客系统》 《十余种编程语言写云笔记》 本系列对比云笔记&#xff0c;将更为简化&#xff0c;去掉了网络调用&#xff0…

数据结构入门(力扣算法)

数据结构入门前面的题号为力扣的题号数组的217. 存在重复元素53. 最大子数组和1. 两数之和88. 合并两个有序数组350. 两个数组的交集 II121. 买卖股票的最佳时机566. 重塑矩阵118. 杨辉三角36. 有效的数独73. 矩阵置零字符串的387. 字符串中的第一个唯一字符383. 赎金信242. 有…

LeetCode 437. 路径总和 III

LeetCode 437. 路径总和 III 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff…

JUC面试(十一)——LockSupport

可重入锁 可重入锁又名递归锁 是指在同一个线程在外层方法获取锁的时候&#xff0c;再进入该线程的内层方法会自动获取锁(前提&#xff0c;锁对象得是同一个对象)&#xff0c;不会因为之前已经获取过的锁还没释放而阻塞。 Java中ReentrantLock和synchronized都是可重入锁&am…

第一章 概述

第一章 概述 1.1 计算机网络在信息时代中的作用 21世纪的一些重要特征 数字化&#xff0c;网络化和信息化 以网络为核心的信息时代 互联网的两个重要基本特点 连通性共享&#xff08;资源共享&#xff09; 1.2 互联网概述 计算机网络由若干个结点货连接这些结点的链路组成…

【唐诗学习】四、边塞诗派代表

四、边塞诗派代表 边塞诗派起源 盛唐是中国历史上一个空前的盛世&#xff0c;国库丰盈&#xff0c;社会十分安定&#xff0c;百姓的幸福指数高。 盛唐是中国历史上一个空前的盛世&#xff0c;国库丰盈&#xff0c;社会十分安定&#xff0c;百姓的幸福指数高。唐太宗以后的几个…

Citadel——Dusk网络的Zero-Knowledge KYC解决方案

1. 引言 近期&#xff0c;Dusk网络宣布其已支持名为Citadel的Zero-Knowledge KYC解决方案&#xff0c;使得用户和机构可控制其权限以及个人信息分享。该架构可用于all claim-based KYC requests&#xff0c;并让用户完全控制他们共享的信息以及与谁共享信息&#xff0c;同时完…

详解Java中的BIO、NIO、AIO

1、 详解Java中的BIO、NIO、AIO 1.1、引言 IO流是Java中比较难理解的一个知识点&#xff0c;但是IO流在实际的开发场景中经常会使用到&#xff0c;比如Dubbo底层就是NIO进行通讯。本文将介绍Java发展过程中出现的三种IO&#xff1a;BIO、NIO以及AIO&#xff0c;重点介绍NIO。…

【c语言进阶】常见的静态通讯录

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a;c语言学习 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对我…

2.H3CNE-网络参考模型

OSI参考模型产生背景各大IT设备厂商只支持自己的私有协议&#xff0c;跨厂商设备兼容性差用户购买和维护成本高不利于网络技术发展概念定义了网络中设备所遵守的层次结构优点开放的标准化接口&#xff0c;协议不再封闭多厂商设备兼容易于理解、学习和更新协议标准实现模块化工程…

【Leetcode刷题】141、环形链表

原题链接&#xff1a;https://leetcode.cn/problems/linked-list-cycle/?favorite2cktkvj给你一个链表的头节点 head &#xff0c;判断链表中是否有环。如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的…

Python数据可视化(二)使用统计函数绘制简单图形

该文会讲解一些大家比较熟悉却又经常混淆的统计图形&#xff0c;掌握这些统计图形可以对数据可视化有一个深入理解&#xff0c;并正确使用。2.1 函数 bar()——用于绘制柱状图函数功能&#xff1a;在 x 轴上绘制定性数据的分布特征。调用签名&#xff1a;plt.bar(x,y)。参数说明…

day21|216.组合总和III、17.电话号码的字母组合

216.组合总和III 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9每个数字 最多使用一次 返回所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。 示例 1: 输入: k 3, n 7 输出: …

说说配置中心

什么是配置中心在微服务的环境下,将项目需要的配置信息保存在配置中心,需要读取时直接从配置中心读取,方便配置管理的微服务工具可以将部分yml文件的内容保存在配置中心一个微服务项目有很多子模块,这些子模块可能在不同的服务器上,如果有一些统一的修改,需要逐一修改这些子模块…

python数据可视化开发:Matplotlib库基础知识

文章目录前言01.工具栏组件02.图表数据03.设置字体字典&#xff08;1&#xff09;全局字体样式&#xff08;2&#xff09;常用中文字体对应名称&#xff08;3&#xff09;查询当前系统所有字体04.图像配置实例05.图表标题06.文本组件07.坐标轴标签组件08.网格组件09.绘制折线10…