第二章 算法和算法分析
程序 = 数据结构 + 算法 要想学好程序设计,可见算法是必不可少的。
算法(algorithm) 是为了解决某类问题而规定的一个有限长的操作序列。
算法的五个特性:
- 有穷性:指算法在执行完有限步骤之后,自动结束而不会出现死循环,并且每个步骤都在可接受时间内完成。
- 确定性:算法的每一步骤都具有正确的含义,不会出现二义性。
- 可行性:算法的每一步都是可行的,也就是说,每一步都能通过执行有限次数完成。
- 输入输出:一个算法有零个或多个输入、一个算法有一个或多个输出。
算法设计的要求:
- 正确性:没有歧义,能正确反映问题需求、能够得到问题的正确答案。
- 可读性:便于阅读、理解和交流。
- 健壮性:当输入数据不合法时,也能做出相关处理,而不至于出现莫名其妙的结果。
- 高效性:时间高效、空间高效。
略:事前、事后分析估算法……我肯定选事前来做算法分析………………
衡量算法效率的度量方法分为时间复杂度和空间复杂度。
冰与火之歌:【时间】与【空间】复杂度
时间复杂度:在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。算法的时间复杂度,也就是算法的时间量度,记作:T(n)= O(f(n))。它表示随问题规模的增大,算法执行时间的增长率和f(n)的增长率相同,称为算法的渐进复杂度,简称为时间复杂度。其中f(n)是问题规模n的某个函数。这样用大写 O() 来体现算法时间复杂度的记法,我们称为大O记法。
推导大O阶的方法:
- 用常数1取代运行时间中的所有加法常数。
- 在修改后的运行次数函数中,只保留最高阶项。
- 如果最高阶项存在且不是1,则去除与这个项目相乘的常数。
- 最后得到的结果就是大O阶。
下面举一些例子:
例1 常数阶 O(1)
{x++;s=0;}
for(int i=0;i<1000;i++)
x++;
第一个语句只有两句语句,所以T(n)= O(1);
第二个语句有一个for循环,但是循环次数是固定的1000次,所以T(n)= O(1)。
例2 线性阶 O(n)
for(int i=0;i<n;i++)
{
x++;
s=0;
}
显而易见, 只有一个循环,循环条件是从1到n,所以T(n)= O(n)。
例3 平方阶 O()
x=0;
y=0;
for(k=1;k<=n;k++)
x++;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
y++;
直接找最复杂的语句块,一看就是循环的嵌套,循环的条件都是从1到n,所以可得:T(n)= O()。
例4 对数阶 O(log2 n)
for(i=1;i<=n;i*=2)
x++;
循环的条件是从1到n,但是每次循环i*=2,所以T(n)= O(log2 n)。
常见的时间复杂度如图所示:
所耗时间从小到大依次是:
我们可以画一个函数图像清晰的看每个复杂度的时间对比:
算法的空间复杂度通过计算算法所需的存储空间实现,算法空间复杂度的计算公式记作:S(n)= O(f(n)),其中,n为问题规模,f(n)为语句关于n所占存储空间的函数。
通常,鉴于运算空间较为充足,我们都会用空间来换时间。 所以,人们都以算法的时间复杂度作为算法优劣的衡量指标。
本博客内容借鉴于:
①《数据结构》 作者:严蔚敏
②《大话数据结构》 作者:程杰