1.3算法和算法的衡量
一、算法
算法是为了解决某类问题而规定的一个有限长的操作序列。一个算法必须满足以下五个重要特性:
1有穷性 2确定性 3可行性 4有输入 5有输出
1有穷性 对于任意一组合法的输入值,在执行有穷步骤之后一定能结束,即:算法中的每个步骤都能在有限时间内完成;
2.确定性
对于某种情况下所应执行的操作,在算法中都有确切的规定,使算法的执行者或者阅读者都能明确其含义及如何执行。并且在任何条件下,算法都只有一条执行路径;
3.可行性
算法中所有的操作必须足够基本,都可以通过已经实现的基本操作运算有限次实现之;
4.有输入
作为算法加工对象的变量值,通常体现为算法中的一组变量。有些输入量需要在算法执行过程中输入,而有的算法表面上可以没有输入,实际上已被嵌入算法之中;
5.有输出
它是一组与“输入”与确定关系的量值,是算法进行信息加工后得到的结果,这种确定关系即为算法的功能。
二、算法设计的原则
设计算法时,通常应考虑到以下目标:
1.正确性 2.可读性 3.健壮性 4.高效率与低存储量需求
1.正确性
首先,算法应当满足特定的“规格说明”方式给出的需求。
其次,对算法是否“正确”的理解可以有以下四个层次:
a.程序中不含语法错误;
b.程序对于几组输入数据能够得出满足要求的结果;
c.程序对于精心选择的、典型、苛刻且带有刁难性的几组输入数据能够得出满足要求的结果;
d.程序对于一切合法的输入数据都能得出满足要求的结果;
通常以c层意义的正确性作为衡量一个算法是否合格的标准。
2.可读性
算法主要是为了人多阅读与交流,其次才是为计算机执行,因此算法的应该利于人的理解;另一方面,晦涩难读的程序易于隐藏较多错误而难以调试;
3.健壮性
当输入数据非法时,算法应当恰当地做出反映或进行相应处理,而不是产生莫名奇妙的输出结果。并且,处理出错的方法不应是中断程序的执行,而应是返回一个表示错误或错误性质的值,以便在更高的抽象层次上进行处理。
4.高效率与低存储量需求
通常,效率指的是算法执行时间;存储量需求指的是算法执行过程中所需的最大存储空间。两者都于问题的规模有关。
三、算法效率的衡量方法和准则
通常有两种衡量算法效率的方法:
事后统计法:
缺点:1.必须执行程序 2.其它因素掩盖算法本质。
事前分析估算法
和算法执行时间相关因素:
1.算法选用的策略
2.问题规模
3.编写程序的语言
4.编译程序产生的机器代码的质量
5.计算机执行指令的速度
一个特定的算法的“运行工作量”的大小,只依赖于问题的规模(通常用整数n表示),或者说,它是问题规模的函数。
假如,随着问题规模n的增长,算法执行时间的增长率和f(n)的增长率相同,则可以记作:T(n)=O(f(n)) 称T(n)为算法的(渐进)时间复杂度
如何估算算的渐进时间复杂度
算法=控制结构+原操作(固有数据类型的操作)
算法的执行时间=∑原操作(i)的执行次数×原操作(i)的执行时间
算法的执行时间与原操作执行次数之和成正比
从算法中选取一种对于所研究的问题来说是基本操作的原操作,以该基本操作在算法中重复执行的次数作为算法运行时间的衡量准则。
例一
for(i= 1; i <= n; ++i)
for( j = 1; j <= n; ++j){
c[i,j]=0;
for(k = 1; i <= n; ++k)
c[i,j] += a[i,k]*b[k,j];
}
基本操作:乘法操作
时间复杂度:O(n^3)
例二
voidselect_sort(int a[n],int n){
//将a中整数序列重新排列成自小至大有序的整数序列
for(i = 0; i < n-1; ++i){
j =i;
for(k = i+1; k < n; ++k)
if(a[k] < a[j])
j = k;
if(j != i)
a[j] ←→ a[i]
}
}//select_sort
基本操作:比较(数据元素)操作
时间复杂度:O(n^2)
语句的频度
例三
voidbubble_sort(int a[],int n){
//将a中整数序列重新排列成自小至大
//有序的整数序列
for(i = n-1, change = TRUE; i>1&& change; --i){
change = FALSE;
for(j = 0; j < i; ++j)
if(a[j] > a[j+1]){
a[j] ←→ a[j+1];
change = TRUE;
}
}
}//bubble_sort
基本操作:赋值操作
时间复杂度:O(n^2)