首先了解一下几个概念。一个是时间复杂度,一个是渐近时间复杂度。前者是某个算法的时间耗费,它是该算法所求解问题规模n的函数,而后者是指当问题规模趋向无穷大时,该算法时间复杂度的数量级。

当我们评价一个算法的时间性能时,主要标准就是算法的渐近时间复杂度,因此,在算法分析时,往往对两者不予区分,经常是将渐近时间复杂度T(n)=O(f(n))简称为时间复杂度,其中的f(n)一般是算法中频度最大的语句频度。

定义:如果一个问题的规模是n,解这一问题的某一算法所需要的时间为T(n),它是n的某一函数 T(n)称为这一算法的“时间复杂性”。

当输入量n逐渐加大时,时间复杂性的极限情形称为算法的“渐近时间复杂性”。

我们常用大O表示法表示时间复杂性,注意它是某一个算法的时间复杂性。大O表示只是说有上界,由定义如果f(n)=O(n),那显然成立f(n)=O(n^2),它给你一个上界,但并不是上确界,但人们在表示的时候一般都习惯表示前者。

此外,一个问题本身也有它的复杂性,如果某个算法的复杂性到达了这个问题复杂性的下界,那就称这样的算法是最佳算法。

“大O记法”:在这种描述中使用的基本参数是 n,即问题实例的规模,把复杂性或运行时间表达为n的函数。这里的“O”表示量级 (order),比如说“二分检索是 O(logn)的”,也就是说它需要“通过logn量级的步骤去检索一个规模为n的数组”记法 O ( f(n) )表示当 n增大时,运行时间至多将以正比于 f(n)的速度增长。

这种渐进估计对算法的理论分析和大致比较是非常有价值的,但在实践中细节也可能造成差异。例如,一个低附加代价的O(n^2)算法在n较小的情况下可能比一个高附加代价的 O(nlogn)算法运行得更快。当然,随着n足够大以后,具有较慢上升函数的算法必然工作得更快。

(一)常数阶时间复杂度O(1)

例1:

Temp=I; i=j; j=temp;

以上三条单个语句的频度均为1,该程序段的执行时间是一个与问题规模n无关的常数。算法的时间复杂度为常数阶,记作T(n)=O(1)。如果算法的执行时 间不随着问题规模n的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是O(1)。

(二)二次时间复杂度O(n^2)

例2:双层for循环的时间复杂度是O(n^2),此例详细分析各个步骤的基本运算次数

sum=0;                (1次运算)---- ①

for(i=1; i<=n; i++)      (1+2n+n*(3m+1)次运算)---- ②

for(j=1; j<=m; j++) (3m+1次运算) ---

sum++;       (1次赋值sum=sum+1 )

解:① 1次运算具体包含1次赋值sum=0,需要1小步执行出结果;

② 外层循环1+2n+n*(3m+1)次运算具体包括一次初始化赋值i=1;n次判断i<=n;n次执行循环体内的语句,而该循环体内有(3m+1)条子语句,故执行循环体内的语句总共需要n*(3m+1)次运算;n次i++自增运算

③ 内层循环3m+1次运算具体包含一次赋值j=1(仅仅初始化时执行1次),m次判断j<=m,m次计算表达式sum++,m次计算j++

④ 阿英注:①和②是在同一个等级的,注意体会下为什么总的运算次数为

1 + 2n + n*(3m +1) + 1!

T(n) = 3*m*n + 3*n + 2 = O(n*m),当m=n时,T(n) = O(n^2)。

⑤ 有疑惑的人,请继续看下面的原因,注意体会一切诸佛说的万法皆空,因果不空,缘起性空,真空妙有!

为什么m*n前面的系数3可以忽略?因为它不是主要矛盾,例如当m*n=300时,3*m*n=900; 当 m*n = 30000时, 3*m*n = 90000。

为什么3*m*n + 3*n + 2 中  3*n + 2 可以忽略? 因为它不是主要矛盾,例如当3*m*n = 9000,3*n+2 = 11,则9000与9000-11差别不大。

结论:对于时间复杂度为T(n)中对n的线性运算(加法和数乘)不影响时间复杂度!

例3:双层for循环的时间复杂度是O(n^2),不考虑线性运算时,简化而实用的时间复杂度计算方法

for (i=1; i<n; i++)

{

y=y+1;        ①

for (j=0;j<=(2*n);j++)

x++;        ②

}

解:  ①的频度是n-1,实际上总共要1+3(n-1)次运算,但这里抓住主要矛盾就行了;

②的频度是(n-1)*(2n+1)=2n^2-n-1

③总的频度是 f(n)=2n^2-n-1+(n-1)=2n^2-2

该程序的时间复杂度T(n)=O(n^2).

(三)线性时间复杂度O(n)

例4:单层循环的时间复杂度为线性时间复杂度O(n)

a=0;   b=1;              ①

for (i=1; i<=n; i++)  ②

{

s=a+b;    ③

b=a;     ④

a=s;     ⑤

}

解:  ① 需要2步操作

② 需要1次赋值操作i=1,n次判断i<=n,执行③④⑤各需要n次,执行i++需要n次,for循环执行下来总共要5*n+1步

T(n)=5*n+1+2=5n+3=O(n).

例5:设一个程序的时间复杂度用一个函数 T(n) 来表示,对于一个查找算法,如下:

int seqsearch( int a[], const int n, const int x)

{

int i = 0;

for (; a[i] != x && i < n ; i++ );

if ( i == n) return -1;

else return i;

}

这个程序是将输入的数值顺序地与数组中地元素逐个比较,找出与之相等地元素。

在第一个元素就找到需要比较一次,在第二个元素找到需要比较2次,…… ,在第n个元素找到需要比较n次。对于有n个元素的数组,如果每个元素被找到的概率相等均为1/n,那么查找成功的平均比较次数为:

f(n) = 1/n (n + (n-1) + (n-2) + ... + 1) = (n+1)/2 = O(n)

(四)对数时间复杂度O( log2(n) )

例6:

i=1;       ①

while (i<=n)

i=i*2; ②

解: 语句1的频度是1,

设语句2的频度是f(n),  则:2^f(n)<=n; f(n)<=log2(n)

取最大值f(n)= log2(n)

T(n)=O( log2(n) )

(五)立方时间复杂度O(n^3)

例6-1:三重循环的时间复杂度为O(n^3)

(1) x=1;

(2) for(i=1;i<=n;i++)

(3)       for(j=1;j<=i;j++)

(4)           for(k=1;k<=j;k++)

(5)               x++;

解:该程序段中频度最大的语句是(5),内循环的执行次数虽然与问题规模n没有直接关系,但是却与外层循环的变量取值有关,而最外层循环的次数直接与n有关,因此可以从内层循环向外层分析语句(5)的执行次数:当i=m时, j 可以取 0,1,...,m-1 ,  所以这里最内循环共进行了0+1+...+m-1=(m-1)m/2次;所以,i从0取到n, 则循环共进行了0+(1-1)*1/2+...+(n-1)n/2=n(n+1)(n-1)/6,则该程序段的时间复杂度为T(n)=O(n3/6+低次项),所以时间复杂度为O(n^3)。

例6-2:求两个n阶方阵的乘积 C=A×B,其算法如下:

# define n 100 // n 可根据需要定义,这里假定为100

void MatrixMultiply(int A[a],int B [n][n],int C[n][n])

{ //右边列为各语句的频度

int i ,j ,k;

(1) for(i=0; i<n;j++) n+1

(2)     for (j=0;j<n;j++) { n(n+1)

(3)       C[i][j]=0; n2

(4)       for (k=0; k<n; k++) n2(n+1)

(5)         C[i][j]=C[i][j]+A[i][k]*B[k][j]; n3

}

}

该算法中所有语句的频度之和(即算法的时间耗费)为:

T(n)=2n3+3n2+2n+1

分析:

   语句(1)的循环控制变量i要增加到n,测试到i=n成立才会终止。故它的频度是n+1。但是它的循环体却只能执行n次。语句(2)作为语句(1)循环体内的语句应该执行n次,但语句(2)本身要执行n+1次,所以语句(2)的频度是n(n+1)。同理可得语句(3),(4)和(5)的频度分别是n2,n2(n+1)和n3。

我们还应该区分算法的最坏情况的行为和期望行为。如快速排序的最坏情况运行时间是 O(n^2),但期望时间是O(nlogn)。通过每次都仔细 地选择基准值,我们有可能把平方情况 (即O(n^2)情况)的概率减小到几乎等于 0。在实际中,精心实现的快速排序一般都能以 (O(nlogn)时间运行。

(六)下面是一些常用的记法

访问数组中的元素是常数时间操作,或说O(1)操作。一个算法如果能在每个步骤去掉一半数据元素,如二分检索,通常它就取 O(logn)时间。用strcmp比较两个具有n个字符的串需要O(n)时间 。常规的矩阵乘算法是O(n^3),因为算出每个元素都需要将n对元素相乘并加到一起,所有元素的个数是n^2。

指数时间算法通常来源于需要求出所有可能结果。例如,n个元素的集合共有2n个子集,所以要求出所有子集的算法将是O(2n)的 。指数算法一般说来是太复杂了,除非n的值非常小,因为,在 这个问题中增加一个元素就导致运行时间加倍。不幸的是,确实有许多问题 (如著名的“巡回售货员问题” ,”汉诺塔问题”),到目前为止找到的算法都是指数的。如果我们真的遇到这种情况, 通常应该用寻找近似最佳结果的算法替代之。

(七) 一个经验规则

有如下复杂度关系

c < log2N < n < n * Log2N < n^2 < n^3 < 2^n < 3^n < n!

其中c是一个常量,如果一个算法的复杂度为c 、 log2N 、n 、 n*log2N ,那么这个算法时间效率比较高 ,如果是 2^n , 3^n ,n!,那么稍微大一些的n就会令这个算法不能动了,居于中间的几个则差强人意. 常见的时间复杂度按数量级递增排列依次为:常数0(1)、对数阶0(log2n)、线形阶0(n)、线形对数阶0(nlog2n)、平方阶0(n2)立方阶0(n3)、…、k次方阶0(nk)、指数阶0(2n)。显然,时间复杂度为指数阶0(2n)的算法效率极低,当n值稍大时就无法应用。

1)基本知识点:没有循环的一段程序的复杂度是常数,一层循环的复杂度是O(n),两层循环的复杂度是O(n^2)? (我用^2表示平方,同理 ^3表示立方);

2)二维矩阵的标准差,残差,信息熵,fft2,dwt2,dct2的时间复杂度: 标准差和残差可能O(n),FFT2是O(nlog(n)),DWT2可能也是O(nlog(n));信息熵要求概率,而dct的过程和jpeg一样。因为和jpeg一样,对二难矩阵处理了.Y=T*X*T',Z=Y.*Mask,这样子,还有分成8*8子图像了;

例7:设n为正整数,利用大"O"记号,将下列程序段的执行时间表示为n的函数。

(1) i=1; k=0

while(i<n)

{

k=k+10*i;

i++;

}

解答:T(n)=n-1, T(n)=O(n), 这个函数是按线性阶递增的。

(2) x=n; // n>1

while (x>=(y+1)*(y+1))

y++;

解答:T(n)=n1/2 ,T(n)=O(n1/2),最坏的情况是y=0,那么循环的次数是n1/2次,这是一个按平方根阶递增的函数。

(3) x=91; y=100;

while(y>0)

if(x>100)

{x=x-10;y--;}

else x++;

解答: T(n)=O(1),这个程序看起来有点吓人,总共循环运行了1000次,但是我们看到n没有? 没。这段程序的运行是和n无关的,就算它再循环一万年,我们也不管他,只是一个常数阶的函数。如果算法的执行时间不随着问题规模n的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是O(1)。

(八)算法的时间复杂度不仅仅依赖于问题的规模,还与输入实例的初始状态有关。

例8:在数值A[0..n-1]中查找给定值K的算法大致如下:

(1) i=n-1;

(2) while(i>=0&&(A[i]!=k))

(3)     i--;

(4) return i;

此算法中的语句(3)的频度不仅与问题规模n有关,还与输入实例中A的各元素取值及K的取值有关:

①若A中没有与K相等的元素,则语句(3)的频度f(n)=n;

②若A的最后一个元素等于K,则语句(3)的频度f(n)是常数0。

(九)一个示例

(1) int num1, num2;

(2) for(int i=0; i<n; i++){

(3)     num1 += 1;

(4)     for(int j=1; j<=n; j*=2){

(5)         num2 += num1;

(6)     }

(7) }

分析:

1.

语句int num1, num2;的频度为1;

语句i=0;的频度为1;

语句i<n; i++; num1+=1; j=1; 的频度为n;

语句j<=n; j*=2; num2+=num1;的频度为n*log2n;

T(n) = 2 + 4n + 3n*log2n

2.

忽略掉T(n)中的常量、低次幂和最高次幂的系数

f(n) = n*log2n

3.

lim(T(n)/f(n)) = (2+4n+3n*log2n) / (n*log2n)

= 2*(1/n)*(1/log2n) + 4*(1/log2n) + 3

当n趋向于无穷大,1/n趋向于0,1/log2n趋向于0

所以极限等于3。

T(n) = O(n*log2n)

阿英讲算法的时间复杂度相关推荐

  1. 算法和时间复杂度概念(一级)

    第一个内容什么是算法?什么是算法的复杂度?什么是算法的空间复杂度?我们的标题是数据结构和算法入门,这两个就是数据结构的入门,这三个就是算法的入门什么叫算法?算法就是指令的集合,是为解决特定问题而规定的 ...

  2. 算法之算法的时间复杂度

    算法之算法的时间复杂度 什么是算法 算法时间复杂度 程序基本操作执行次数 渐进时间复杂度 时间复杂度是指执行算法所需要的计算工作量,想要了解算法的时间复杂度不妨先看看到底什么是算法. 什么是算法 &l ...

  3. 谈谈算法的时间复杂度

    问题一:我们如何判断一个算法的优劣? 答:在不考虑额外空间开销的情况小,对于同一个问题,直观而言,解决这个问题的算法需要的时间越少,我们就可以认为这个算法的效率越高. 就比如:如果我们需要在有序数组a ...

  4. 如何计算算法的时间复杂度

    原地址:http://www.nowamagic.net/librarys/veda/detail/2195 在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变 ...

  5. 【数据结构入门】算法的时间复杂度和空间复杂度详解

    文章目录 (1)算法效率 (2)时间复杂度的计算 1)什么是时间复杂度 2)大O渐进表示法(估算) 3)时间复杂度计算实例 4)总结 5)一些思考 (3)空间复杂度的计算 (4)常见复杂度对比 本篇前 ...

  6. 第二讲 算法思想的发展历程

    第二讲   算法思想的发展历程 教学目标与教学指导: 算法思想源远流长,中国古代数学中就蕴涵了丰富的算法思想.随着现代信息技术飞速发展,算法在科学技术.社会发展中发挥着越来越大的作用,并且日益融入社会 ...

  7. 各个排序算法及其时间复杂度

    各个排序算法及其时间复杂度 一.内部排序: 1.稳定的排序算法 1.1 冒泡排序 1.1.1 冒泡排序流程 1.1.2 冒泡排序的实现 1.2 插入排序 1.2.1 插入排序流程 1.2.2 插入排序 ...

  8. 算法的时间复杂度分析

    算法的时间复杂度是一个函数,它定性描述该算法的运行时间.这是一个代表算法输入值的字符串的长度的函数.时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数.使用这种方式时,时间复杂度可被称为是渐 ...

  9. 算法的时间复杂度解惑

    前言 算法很重要,但是一般情况下做移动开发并不经常用到,所以很多同学早就将算法打了个大礼包送还给了老师了,况且很多同学并没有学习过算法.这个系列就让对算法头疼的同学能快速的掌握基本的算法.过年放假阶段 ...

最新文章

  1. 有趣的计算机课的作文,有趣的电脑课作文500字
  2. 你看的每一篇Nature论文,都是这样出炉的!
  3. hibernate主配置文件中指定session与当前线程绑定
  4. Mysql 日志系统 redo log 和 binlog
  5. 云平台已经成为发生网络攻击的重灾区
  6. python 多分类逻辑回归_机器学习实践:多分类逻辑回归(softmax回归)的sklearn实现和tensorflow实现...
  7. 计算机视觉与深度学习 | 目标提取(代码实现)
  8. 以计算机谈人文科学,阅读下面一段文字,完成问题   自20世纪80年代以来,世界都在谈“软科学技术”,何谓软科学?经常听人说:“脑子不够使。”这其实就是对软科学的需求。于是,从古至今,...
  9. 向左向右向后转python_Turbot与python教程-实现左向旋转
  10. HITOJ 2662 Pieces Assignment(状压DP)
  11. wangeditor php上传本地图片,wangEditor 本地上传图片配置
  12. html+javascript实现数字微调,点击一下增加1或减去1
  13. linux和windows精简版,win7 64/86 超级精简版877MB -三蛋作品
  14. 高通android logo,高通平台android kernel 开机logo展示和传统linux一样
  15. 场景编辑器 Scene Building
  16. 数能一体化物联网感知层路由协议研究
  17. 使用U盘制作纯dos系统
  18. 打开Idea,弹出Server‘s certificate is not trusted 解决方法
  19. 1999.00 php,CBA20周年之1999-00赛季-前卫先合并后解散 八一5连冠
  20. scala windows搭建开发环境

热门文章

  1. 【Pygame实战】嗷大喵历险记之程序员吸猫指南:真的太上头了~
  2. 2.23 haas506 2.0开发教程 - KeyPad - 矩阵键盘(仅支持M320开发板)
  3. 飞桨领航团AI达人创造营第三课笔记
  4. 测试中文编码_如何通过带回家的编码测试
  5. 【商品架构day5】淘宝:TOP1的商品系统长什么样子
  6. 微信小程序导入其他字体会不会影响运行_微信小程序是否可以引用特殊字体
  7. 合并表格文件的简单方法
  8. Android Studio连接安卓手机驱动
  9. 英语c开头语言,C开头的英语短语集锦
  10. (四)万能的搜索 —— 3. 广度优先搜索