文章目录
- 第二节概览
- 什么是算法?
- 算法的5个特性?
- 算法如何评估?
- 时间指标如何衡量?
- 算法的复杂度如何度量?算法开销上限和下限如何表示?
- 什么是常数复杂度?线性操作?对数复杂度-线性对数?多项式复杂度?指数复杂度?
- 渐进时间复杂度的作用是什么?
- 光知道数据规模还不够,数据排列的混乱程度也会增加时间复杂度?最优,最差,平均时间复杂度?
- 空间复杂度如何衡量?什么时候需要衡量?
第二节概览
什么是算法?
算法的思想是计算机程序的灵魂,
算法规定的流程决定着程序的执行步骤。
使用辗转相除法求两个正整数最大公因子的欧几里得算法,出现在2300多年前,这是目前已知的最古老的算法。
定义1-1 算法是一个由若干确定的(无二义性的)、可执行的步骤组成的肯定能够终止的有序步骤集合。
算法描述一个问题的求解过程,由一系列解决问题的清晰指令构成。
这些指令可以使用自然语言表示也可以使用计算机程序设计语言表示,甚至可以混合使用自然语言与计算机程序设计语言来描述。
C语言与自然语言的混合有时称为类C语言,这样描述的算法称为伪代码。
在计算机问世之后,人们将一些问题交给计算机来求解,但计算机不能识别上述那样描述的算法,所以很多算法要具体化为一个计算机程序,
程序是算法的另一种表现形式。
(本书采用C语言实现相关的算法)
- 看来得先学学C语言
算法的5个特性?
算法是一系列指令的描述,但并不是任意的描述都可以构成算法。算法必须满足如下5个重要特性。
1、输入:有0或多个输入值。
也就是说算法可以没有输入
2、输出:有1或多个输出值。
也就是说算法必须有输出,没有输出,不叫算法
通常输出的是算法的执行结果
3、有穷性:一个算法必须在执行有穷步骤之后结束。
实现算法的程序的运行时间是有限的
4、确定性:算法的每一个步骤都必须有确切的含义。
算法的每个执行步骤不能有歧义
5、可行性:算法中要做的运算都是相当基本的、能够精确进行的。
算法的每个执行步骤必须是能够执行的
算法如何评估?
算法必须正确,错误的算法不可能得到正确的求解结果。
- 所以,算法的正确性成为评判算法的首要指标
(为简单起见,本书中只对正确的算法进行评判)
除此之外,还要评判算法的其他方面,包括它的执行效率。
在使用计算机解决问题时,总会要求所花的时间越短越好,占用的计算机资源越少越好。
除了正确性以外,多、快、好、省也都是一直追求的目标。
那么,计算机内部的资源有哪些呢?CPU时间和内存空间肯定是紧俏的两种资源。
- 一般地,分别使用时间复杂度和空间复杂度来评估这两种资源的使用效率。
时间指标如何衡量?
1、屏蔽计算机硬件的差异性,也就是指令集的差异性,简化问题,才能加以衡量
为了突出算法自身的特点,故在衡量算法效率时应该屏蔽计算机的差异性,不能使用程序运行的绝对时间作为衡量指标。
一般地,选择算法执行的机器指令个数作为衡量指标相对合理一些。
计算机的CPU芯片不同,运行的系统不同,导致指令集也可能不同。
- 将机器指令再进一步对应为程序中的语句,统计一个程序在执行期间需要执行的语句总数,将这个数值作为衡量算法的时间指标。
2、屏蔽程序中不同语句的差异性,约定以基本语句为准,简化问题,才能加以衡量
并且约定,程序设计语言中一条基本语句的执行时间为1个单位时长,
这样处理后将不同语句之间的差异也屏蔽掉了。
一个算法的时间效率可以用问题规模及关键的处理步骤的多少来定义。
- 具体来说,将算法的时间效率表示为问题规模n的一个解析式,对于规模为n的问题,解析式计算的值就是算法处理的步骤数。
将关于n的这个解析式称为增长函数,表示为T(n)。
对于一个具体的算法,其增长函数是一个近似的表达式。
一个算法处理10个数据时,是执行了100条语句还是102条语句,差别并不大。
需要关心的是,当数据量增大若干倍时,算法所花费的时间需要增加多少倍,即需要知道其中的比例关系。
这是函数的渐近性,即增长函数与问题规模的变化关系,也就是想知道n增大时函数的一般特性。
算法的复杂度如何度量?算法开销上限和下限如何表示?
1、
定义 1 − 2 : 称 ( 复杂度 ) 函数 T ( n ) ,也就是增长函数 T ( n ) 是 O ( f ( n ) ) 的,即 T ( n ) = O ( f ( n ) ) ,这里的关键是 f ( n ) ;为什么用 f ( n )来表示,因为 T ( n ) 表示的函数,可能本身有简单函数,也有复杂函数 如果存在常数 c > 0 与 n 0 ,就是有个常数 c ,还有 n 0 , n 0 不就是问题规模 当 n > n 0 时,也就是问题规模,比 n 0 大 有 T ( n ) ≤ c f ( n ) ; T ( n ) 就是增长函数,要比首先是 f ( n ) ,再是 c ,这两者的乘积,增长函数比这个小 例如, T 1 ( n ) = n + 1 2 = O ( n ) , T 2 ( n ) = 3 n 2 + 4 n + 5 = O ( n 2 ) 。 当然, T 1 ( n ) = O ( n 2 ) , T 2 ( n ) = O ( n 3 ) 也都是对的,但一般取最低阶表示。 由此可以看出, T ( n ) = O ( f ( n ) ) 说明 T ( n ) 的阶不大于 f ( n ) 的阶。 定义1-2:\\ 称(复杂度)函数T(n),也就是增长函数T(n)\\ 是O(f(n))的,即T(n)=O(f(n)),这里的关键是f(n);为什么用f(n)来表示,因为T(n)表示的函数,可能本身有简单函数,也有复杂函数\\ 如果存在常数c>0与n_0,就是有个常数c,还有n_0,n_0不就是问题规模\\ 当n>n_0时,也就是问题规模,比n_0大\\ 有T(n)≤cf(n);T(n)就是增长函数,要比首先是f(n),再是c,这两者的乘积,增长函数比这个小\\ 例如,T_1(n)=\frac{n+1}{2}=O(n),\\ T_2(n)=3n^2+4n+5=O(n^2)。\\ 当然,T_1(n)=O(n^2),T_2(n)=O(n^3)也都是对的,但一般取最低阶表示。\\ 由此可以看出,T(n)=O(f(n))说明T(n)的阶不大于f(n)的阶。 定义1−2:称(复杂度)函数T(n),也就是增长函数T(n)是O(f(n))的,即T(n)=O(f(n)),这里的关键是f(n);为什么用f(n)来表示,因为T(n)表示的函数,可能本身有简单函数,也有复杂函数如果存在常数c>0与n0,就是有个常数c,还有n0,n0不就是问题规模当n>n0时,也就是问题规模,比n0大有T(n)≤cf(n);T(n)就是增长函数,要比首先是f(n),再是c,这两者的乘积,增长函数比这个小例如,T1(n)=2n+1=O(n),T2(n)=3n2+4n+5=O(n2)。当然,T1(n)=O(n2),T2(n)=O(n3)也都是对的,但一般取最低阶表示。由此可以看出,T(n)=O(f(n))说明T(n)的阶不大于f(n)的阶。
- 这个例子不太明白
意思可能是,T(n)的阶不可能超过f(n)的阶数
2、
定义 1 − 3 : 称 ( 复杂度 ) 函数 T ( n ) ,也就是增长函数 T ( n ) 是 Ω ( f ( n ) ) 的,即 T ( n ) = Ω ( f ( n ) ) ,这里的关键是 f ( n ) 如果存在常数 c > 0 与 n 0 ,就是有个常数 c ,还有 n 0 , n 0 不就是问题规模 当 n > n 0 时,也就是问题规模,比 n 0 大 有 T ( n ) ≥ c f ( n ) ; T ( n ) 就是增长函数,要比首先是 f ( n ) ,再是 c ,这两者的乘积,增长函数比这个大 例如, T 1 ( n ) = n + 1 2 = Ω ( n ) , T 2 ( n ) = 3 n 2 + 4 n + 5 = Ω ( n 2 ) 。 当然, T 1 ( n ) = Ω ( 1 ) , T 2 ( n ) = Ω ( n ) , T 2 ( n ) = Ω ( n l o g n ) 也都是对的,但一般取最高阶表示。 由此可以看出, T ( n ) = Ω ( f ( n ) ) 说明 T ( n ) 的阶不小于 f ( n ) 的阶。 定义1-3:\\ 称(复杂度)函数T(n),也就是增长函数T(n)\\ 是Ω(f(n))的,即T(n)=Ω(f(n)),这里的关键是f(n)\\ 如果存在常数c>0与n_0,就是有个常数c,还有n_0,n_0不就是问题规模\\ 当n>n_0时,也就是问题规模,比n_0大\\ 有T(n)≥cf(n);T(n)就是增长函数,要比首先是f(n),再是c,这两者的乘积,增长函数比这个大\\ 例如,T_1(n)=\frac{n+1}{2}=Ω(n),\\ T_2(n)=3n^2+4n+5=Ω(n^2)。\\ 当然,T_1(n)=Ω(1),T_2(n)=Ω(n),T_2(n)=Ω(nlogn)也都是对的,但一般取最高阶表示。\\ 由此可以看出,T(n)=Ω(f(n))说明T(n)的阶不小于f(n)的阶。 定义1−3:称(复杂度)函数T(n),也就是增长函数T(n)是Ω(f(n))的,即T(n)=Ω(f(n)),这里的关键是f(n)如果存在常数c>0与n0,就是有个常数c,还有n0,n0不就是问题规模当n>n0时,也就是问题规模,比n0大有T(n)≥cf(n);T(n)就是增长函数,要比首先是f(n),再是c,这两者的乘积,增长函数比这个大例如,T1(n)=2n+1=Ω(n),T2(n)=3n2+4n+5=Ω(n2)。当然,T1(n)=Ω(1),T2(n)=Ω(n),T2(n)=Ω(nlogn)也都是对的,但一般取最高阶表示。由此可以看出,T(n)=Ω(f(n))说明T(n)的阶不小于f(n)的阶。
大O表示法和大Ω表示法分别描述某一算法的上限(如果能找到某一类输入下开销最大的函数)
和下限(如果能找到某一类输入下开销最小的函数)。
当上、下限相等时,可用表示法。
如果一种算法既是O(f(n))的又是Ω(f(n))的,则称其是**(f(n))**的。
什么是常数复杂度?线性操作?对数复杂度-线性对数?多项式复杂度?指数复杂度?
1、
若增长函数不随算法问题规模变化,即不管问题规模有多大,花费的时间都是固定的,
则增长函数称为O(1)阶,或称常数复杂度。
2、
与问题规模成正比的问题求解算法称为线性操作。
3、
许多算法具有 l o g 2 n 的对数复杂度。 许多算法具有log_2n的对数复杂度。\\ 许多算法具有log2n的对数复杂度。
4、
其他算法有 n 的某次幂的多项式复杂度,如 O ( n 2 ) 或 O ( n 3 ) 。 其他算法有n的某次幂的多项式复杂度,如O(n^2)或O(n^3)。\\ 其他算法有n的某次幂的多项式复杂度,如O(n2)或O(n3)。
5、
更坏的算法是指数复杂度, n 是指数,如 0 ( 2 n ) 。 更坏的算法是指数复杂度,n是指数,如0(2^n)。 更坏的算法是指数复杂度,n是指数,如0(2n)。
表1-2中列出了几种增长函数及它们的渐近时间复杂度(即时间复杂度)。
1、常数,就是一条横线,不会上升
2、线性,其实这个线性已经上升得很快了
3、到了线性对数,这对数,在值很大的时候,确实会比线性的,陡峭一些
4、再到多项式,就更加陡了
5、到了指数,基本上贴近于坐标轴了
一些增长函数和它们的时间复杂度
渐进时间复杂度的作用是什么?
渐近时间复杂度对算法的意义是什么呢?
它直接影响计算机能力提升后能够处理的数据量增长的大小。
假定有不同时间复杂度的4个算法:A、A2、A,和A
当计算机的处理能力提升至原来的10倍时,
2、线性复杂度算法
具有0(n)时间复杂度的算法A,处理的数据量确实增长至原来的10倍,也就是问题规模扩大至原来的10倍。
4、多项式复杂度算法
但具有 O ( n 2 ) 时间复杂度的算法 A 2 ,问题规模只扩大至原来的 3.16 倍。 但具有O(n^2)时间复杂度的算法A2,问题规模只扩大至原来的3.16倍。 但具有O(n2)时间复杂度的算法A2,问题规模只扩大至原来的3.16倍。
5、指数复杂度算法
对于具有指数阶的算法A4,其问题规模几乎没有什么改变。
因处理器的处理速度提升而带来的改善比例,敌不过低效率算法导致的速度减弱。
;意思也就是,复杂度越高的算法,会让升级硬件花的钱浪费掉,钱花了实际效率并不会提升多少
光知道数据规模还不够,数据排列的混乱程度也会增加时间复杂度?最优,最差,平均时间复杂度?
在具体到一个问题时,即使知道了初始数据的个数,所花费的时间也可能是不一样的。
例如,在对10000个整数进行排序时,如果这10000个整数已经按大小排列好了,那么排序过程将非常简单,所花费的时间也最少。
- 同样地,可能会有某一种排列情况,使得排序时所花费的时间最多。
如果考虑每种排列情况,则可以综合评判它们的平均情况。
由此得到时间复杂度的细化指标。
当问题规模确定后,时间花费最少的称为最优时间复杂度或最好时间复杂度,
时间花费最多的称为最坏时间复杂度或最差时间复杂度,
所有情况下的平时花费时间称为平均时间复杂度。
空间复杂度如何衡量?什么时候需要衡量?
除了要评判算法的时间复杂度以外,算法在运行过程中临时占用的空间大小也要考虑,这称为空间复杂度。
一般地,空间复杂度也表示为问题规模的一个函数。
1、注意,是不包含,也就是屏蔽算法代码占用的空间,屏蔽算法中初始数据占用的存储空间
在考虑空间存储量时,算法代码占用的空间、算法中初始数据占用的存储空间,都不包含在内。
有些算法,除数据本身占据的空间以外,需要额外分配的空间并不多,可能只是一个定数,并不依问题规模而改变。
此时,关注的重点只在算法的时间复杂度上。
- 只有当一个算法需要的额外空间数量依赖于问题规模时,才考虑它的空间复杂度。