作者:低调
作者宣言:写好每一篇博客

文章目录

  • 前言
  • 一、什么是时间复杂度?
    • 1.1时间复杂度的概念
    • 1.2复杂度计算在算法的意义
    • 1.3如何计算常见算法的时间复杂度?
  • 二、常见时间复杂度计算举例
  • 三、oj练习题
  • 总结

前言

时间复杂度是数据结构最开始学的一章,我相信大部分人和我一样,刚开始学,或者已经学完这一章,都还不理解这个是什么意思,怎么计算时间复杂度,接下来,我将为大家进行详细的介绍,看看我能不能把你们讲懂:


以下是本篇文章正文内容,下面案例可供参考

一、什么是时间复杂度?

我们通常说时间复杂度是建立在算法效率上的,所以也叫算法的时间复杂度。

什么是算法效率?

算法效率分析的目的是看算法实际是否可行,并在同一个问题存在多个算法时,可进行时间和空间性能上的比较,以便从中挑选出较优的算法

算法效率分析分为两种:第一种是时间效率,第二种是空间效率。时间效率被称为时间复杂度,空间效率被称作空间复杂度。 时间复杂度主要衡量的是一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额外空间(由于现在计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度,此文也就不在讲解空间复杂度了)

1.1时间复杂度的概念

注:在计算机科学中,算法的时间复杂度是一个函数,需要把程序放到计算机上运行才能得出结果,很显然这样是非常麻烦的。

所以我们才有了时间复杂度这个分析方式,一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。

1.2复杂度计算在算法的意义

虽然我们现在写的程序很快运行出来了,但在今后工作中,我们会面临几十万行代码,这个时候就体现到算法效率的意义,和计算时间复杂度的重要性了。在以后面试过程中,也需要掌握怎么计算,才能顺利通过面试。

1.3如何计算常见算法的时间复杂度?

大O的渐进表示法

我们先来看一个简单的代码:

// 请计算一下Func1基本操作执行了多少次?
void Func1(int N) {int count = 0;for (int i = 0; i < N ; ++ i)//执行N次{for (int j = 0; j < N ; ++ j)//执行N次,并且这个for在另一个for内部{++count;}}for (int k = 0; k < 2 * N ; ++ k)//执行2N次{++count;}int M = 10;while (M--)//执行十次;{++count;}printf("%d\n", count);
}

Func1 执行的基本操作次数:F(N)=N×N+2*N+10
N = 10 F(N) = 130
N = 100 F(N) = 10210
N = 1000 F(N) = 1002010
*实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里我们使用大O的渐进表示法。
*大O符号(Big O notation):是用于描述函数渐进行为的数学符号。

推导大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
使用大O的渐进表示法以后,Func1的时间复杂度为:
O(N*N)
N = 10 F(N) = 100
N = 100 F(N) = 10000
N = 1000 F(N) = 1000000

通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执
行次数。
另外有些算法的时间复杂度存在最好、平均和最坏情况:
最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)
例如:在一个长度为N数组中搜索一个数据x
最好情况:1次找到
最坏情况:N次找到
平均情况:N/2次找到
在实际中一般情况关注的是算法的最坏运行情况,所以数组中搜索数据时间复杂度为O(N)

相信大家也会计算出O(2*N)
当N特别大的时候,N和2N差距也是特别大,这就有人会说不应该把2去掉。
这里给大家举个例子:大家可以去网上搜搜,现在腾讯市值大约值 4 5万亿,而百度市值大约值五千亿,两个集体的老总同时买最贵的别墅,是不是都买得起。所以这个不是影响。当N特别大的时候,这种差距也就不约而同了。这个你们也可以将给你们的同学听听。

二、常见时间复杂度计算举例

话不多说直接上代码:
1.

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

F(N)=M+N;
时间复杂度O(M+N);

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

F(N)=100;
时间复杂度为O(1);

3.冒泡排序

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

当end=n时,第二个for执行n-1次
当end=n-1时, 第二个for执行n-2次
……
当end=2时,第二个for执行1次
F(N)=1+2+…+n-1;
这是一个等差数列求和,最高次方为N×N;
时间复杂度为O(N*N)

注:当是有序的时候,时间复杂度为O(N);
因为这个代码做了优化,当end=n时,当第二个for循环走完后,因为是有序的,不会进入if语句,所以exchange不会发生改变,就会进入第二个if语句,直接退出循环,所以当有序的时候第一个for只执行了一次,第二个for执行了n-1次,所以是时间复杂度为O(N);

4.二分查找

// 计算BinarySearch的时间复杂度?
//也叫二分查找(折半查找算法)
int BinarySearch(int* a, int n, int x) {assert(a);//断言,如果数组a为空,就直接断言出去int begin = 0;int end = n;while (begin < end){int mid = begin + ((end-begin)>>1);//这是位移操作符>>1//右移一个比特位,相当于除了2if (a[mid] < x)begin = mid+1;else if (a[mid] > x)end = mid;elsereturn mid;}return -1;}

设X为要查找的次数,大家可以想象将一张纸对折对折在对折,就类似折半查找
举个例子:当N=16时,第一次循环没找到,N=8,第二次循环没找到,N=4,第三次循环没找到,N=2;第四次要么找到了,要么没有找到。
F(N)=2的X次方;(这里次方符合不太好打出来,望读者见谅)
X=logN;(通常2可省略不写)
时间复杂度O(logN);

注:希望读者仔细看着代码去理解。

5.阶乘的递归

// 计算阶乘递归Factorial的时间复杂度?
long long Factorial(size_t N) {return N < 2 ? N : Factorial(N-1)*N; }

我们以N=4为例

大家可以看到,递归了四次就完成了计算
F(N):递归次数*每次递归函数的次数;
时间复杂度O(N);

不理解的可以自己在下去画画递归展开图

6.斐波那契数列

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

注:1 1 2 3 5 8 13……后一个数是前两位数的和,叫做斐波那契数列。

我们以求第四个斐波那契数为例
大家应该可以清晰的看到第一层只有一次递归,第二层优两次递归。第三层就四次递归;
F(N)=2的0次方+2的1次方+……+2的n-1次方=2的n次方-1
时间复杂度O(2的n次方)

达到2的n次方,可以说效率非常低了,当求第50个的数时,就要运算2的50次方次,cpu的运行大约只有上亿次,出现这种效率低的原因是因为每一次递归需要建立栈帧,递归需要消耗空间,说白了就是以空间换取时间。

接下来我给大家弄一个优化版

int Fib(int n){int a,b,c=1;
while(n>2)
{  c=a+b;a=b;b=c;n--;}return c;

这样时间复杂度O(N),这样大大提高了运行效率。

我们还有常见的还有O(N*logN),快速排序,希尔排序都是符合这样的时间复杂度。大家可以自己下去了解一下。

注:效率依次从高倒低是:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<…<Ο(2n)

三、oj练习题


这一题最基本的思想就是就是一个一个数的遍历,先遍历一次找到一个数,在遍历一遍找到第二个消失的数,这样时间复杂度就是O(N*N),但题目要求时间复杂度是O(N),
所以我们有必须环一种思路,先看代码,我在来给大家解释:

int missingNumber(int* nums, int numsSize){int x=0;
for(size_t i=0;i<numsSize;i++)
{x^=nums[i];
}
for(size_t i=0;i<=numsSize;i++)
{x^=i;
}
return x;
}

我们利用了异或的特性,相同为0,相异为一,X同时异或两个数就为0,0与任何数异或等于任何数,题目说是0-n的数,举个例子:
0 1 2 3 4 5 6 8 9
我们所要找的数字是7,我们让X与上面这个数组先疑惑,
在与完整0 1 2 3 4 5 6 7 8 9进行疑惑,大家可以看到除了7,所有数都和X异或了两次,变成了0,所有我们找到了消失的数字。如果大家不明白X与一个数异或两次为什么为0的话,我在给大家画个图,来进一步的理解:

相信大家看到这里应该理解了吧!

总结

上述是我总结一些关于时间复杂度的概念,计算和习题,让我们对时间复杂度不在感到陌生,也让我们明白了时间复杂度的重要性,希望读者看完这篇文章再去看看之前学的,不会计算的时间复杂度,现在会了没有,对于刚接触的也是可以去尝试看一下,如果我写的有不对的地方,也希望你们指出来。让我们一起学习进步吧!

你还在为时间复杂度不懂而担心吗???赶紧进来,这里手把手教你计算时间复杂度!!!相关推荐

  1. 看完此文再不懂区块链算我输:手把手教你用Python从零开始创建区块链

    导读:如果你还没有听说过 3 点钟区块链群,说明你还不是链圈的人:如果你还没有加入 3 点钟区块链群,说明你还不是链圈的大佬:如果你还没有被 3 点钟区块链群刷屏,说明你还体会不到什么是"币 ...

  2. 不懂怎么搞定人的进来:年业绩千万的老销售给你几招实惠的-没有干货立即跳楼

    不懂怎么搞定人的进来:年业绩千万的老销售给你几招实惠的-没有干货立即跳楼 作者:大海贼弯刀 日期:2012-3-14 9:40:00     开门见山!老子不写什么职场小说的,现实一样能搞的够彩头. ...

  3. ansys如何删除线_绘画新手不懂如何用ps提取线稿?教你用PS提取自己喜欢的线稿!...

    绘画新手不懂如何用ps提取线稿?初学者如何自学绘画?自学板画难吗?怎样才能学习好绘画?想必这些都是绘画初学者们经常在想的问题吧,就是不知道如何才能学习好绘画,然后绘画出自己想要画的东西 那么今天灵猫课 ...

  4. 计算时间复杂度--(简单版)

    步骤: 1.找到执行次数最多的语句 2.语句执行语句的数量级 3.用O表示结果 计算时间复杂度的3个出发点,掌握这三个出发点,那么一向搞不懂的时间复杂度就可以迎刃而解啦. 然后: 1.用常数1取代运行 ...

  5. 手把手带你了解时间复杂度和空间复杂度 【超详细】

    目录 前言 为什么要学习复杂度? 一. 算法效率 二.时间复杂度 2.1时间复杂度概念 2.1大O的渐进表示法 2.2常见时间复杂度计算举例 三. 空间复杂度 3.1空间复杂度的概念 3.2常见空间复 ...

  6. axurehtml打开不用用_还有人花钱买会员看剧?赶紧用iPhone免费追剧

    对于小租来说,没有什么比下班宅在家边吃边刷剧更开心的事了. 然而每次当小租看得正欲罢不能的时候,发现需要充值VIP才能解锁接下来的续集,心情真是大起大落. "都看到这里了,怎么能断了呢?&q ...

  7. 手把手教你完成CSDN对接百度统计 看完这篇文章你还不会对接 欢迎您提刀顺着网线来砍我!!!!

    大家好,我是:じ☆ve朽木,开发经验都是一步一步慢慢积累的,没有谁生来就具有的,只要我们付出了努力,肯定就会有收获!进入我的博客,带你了解Java知识,js小技巧,带你玩转高端物联网.博客地址为:じ☆ ...

  8. 时间插件只能选择整点和半点_我花一小时自制了三款PPT插件,不仅免费分享,还想手把手教你制作...

    更准确的说,三顿花一小时给PPT里这个天天和你见面的功能区做了一次彻底的整容: 我精简了好多根本用不到的功能,还添加了一大波可以让你效率翻倍的一键操作,比如一键拆分文字,一键美化图表等等. 这样的改头 ...

  9. cmd 将文件夹下文件剪切到另外一个文件_手把手教你运行第一个 Java 程序,看不懂你来骂我!...

    码字不易,对你有帮助 **点赞 /转发↪️/关注 ** 支持一下作者 微信搜公众号:不会编程的程序圆br/>看更多干货,获取第一时间更新 在运行第一个 java 程序之前,你需要先将 java ...

最新文章

  1. wxpython应用程序对象与顶级窗口_wxPython 基础 | 学步园
  2. Free Download Manager (FDM) 中文版 - 替代迅雷最佳免费开源下载工具软件
  3. 干货!华为AutoML助力AI开发效率提升攻略
  4. listagg 函数--oracle 11g release 2
  5. Linux命令行参数前加--,-和不加杠
  6. SqlServer数据组织结构
  7. ubuntu下编译安装mysql记录
  8. 月薪2万是一种怎样的人生体验?
  9. 航模飞机设计基础知识
  10. 基于R语言的Meta分析(全流程、不确定性分析)方法与Meta机器学习
  11. gxworks2使用指令手册_编程软件GX-Works2简单工程功能块篇操作手册三菱GX-Works2手册 - 广州凌控...
  12. 被 YYUC $is_developing 害惨了.
  13. 字符串的编码格式转换
  14. 在Sbo Add-on插件中实现通用的模态数据选择
  15. Andriod8.0去除Launcher谷歌搜索框
  16. maven-assembly-plugin
  17. 网易云音乐-面临百万请求的最优方案(公开课-笔记)
  18. vue3 Component inside <Transition> renders non-element root node that cannot be animated.
  19. linux启用dcb步骤,Linux内核DCB子系统
  20. Hadoop查看文件个数文件大小文件夹大小

热门文章

  1. 生命无常,请别辜负好时光!
  2. 近期讨论的“星巴克咖啡致癌”?
  3. 有关ORA600错误的参数的解释文档
  4. redis渐进式rehash机制
  5. 实习-VPN表单-前端后端数据库-1
  6. 消防应急疏散指示系统在广场住宅区项目的应用
  7. 深信服EDR远程命令执行
  8. 自动驾驶仿真(Matlab)
  9. IntelliJ IDEA插件php golang python shell docker ignore UML plantuml等插件安装
  10. 「节能学院」Acrel-7000企业能源管控平台在某公司的应用