一 算法的设计目标
正确性:满足具体问题的解,基本目标。
可读性:有利于人去理解算法
健壮性:输入非法数据,能适当做出处理,不产生莫名其妙的输出
高效性:包括时间的高效性和空间的高效性
二算法性能指标
算法的时间效率也成为时间复杂度。
算法的空间效率也成为空间复杂度
同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。算法分析的目的在于选择合适算法和改进算法。一个算法的评价主要从时间复杂度和空间复杂度来考虑。
算法时间的高效性和空间的高效性通常是矛盾的。所有一般只会取一个平衡点。
通常我们假设程序运行在内存中,且内存容量足够使用,所以更多的讨论时间复杂度。
二 时间复杂度
算法的时间复杂度反映了算法执行的时间长短。度量一个算法在计算机上执行的时间通常有两种方式
1事后统计法
2事前分析法:(常用)
包括:编写算法使用的高级语言 2编程产生的机器语言代码质量 3 机器指令执行速度 4问题规模
O()函数
表示算法的时间效率与算法所处理的数据元素个数n函数关系 的最常用函数O()函数
一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。
当算法的时间复杂度T(n)与问题规模n无关时,此时算法的时间复杂度T(n)=O(1)。
2.1计算下列算式的前N项和
1-2+3-4+5.....+N
分析:当N为奇数时,和为:(N+1)/2
当N为偶数时,和为:-N/2
2.2设数组a和b在前面部分已经赋值,求如下两个n阶矩阵相乘算法的时间复杂度 for(i=0;i<n;i++) { for(j=0;j<n;j++) { c[i][j]=0; //基本语句1 for(k=0;k<n;k++) { c[i][j]=c[i][j]+a[i][k]*b[k][j];//基本语句2 } } } 假设基本语句 c[i][j]=0为c1, c[i][j]=c[i][j]+a[i][k]*b[k][j]为c2 f(n)=c1*n2+c2*n3 ,所以T(n)=O(n3)
2.3 设n为如下算法处理的数据元素个数,求算法时间复杂度。 for(i=1;i<=n;i=i*2) { System.out.println(i); } 分析:执行次数为2f(n)<=n; f(n)<=log2n 所以T(n)=O(log2n)
2.4:分析冒泡排序算法的时间复杂度 public class Bubblesort { static void bubblesort(int[] a) { int temp; for (int i = 0; i < a.length-1; i++) { //-1是因为最后一个没必要再跟它本身比较 for (int j = 0; j < a.length-i-1 ; j++) { if (a[j] > a[j+1]) { temp = a[j]; a[j] = a[j+1]; a[j+1] = temp; } } } } 最坏的情况:若记录序列的初始状态为"逆序",则需进行n(n-1)/2次比较和记录移动。 } 所以冒泡排序算法的时间复杂度T(n)=O(n2)
冒泡排序的例子
public class BubbleSort { //冒泡排序算法,通过flag变量判断排序是否提前结束。 public static void BubbleSort(int arr[]) { int n = arr.length; int i, j, temp, flag; flag = 1;//flag:1表示排序没有结束,0表示排序已经结束 for (i = 1; i < n && flag == 1; i++) { for (j = 0; j < n - i; j++) { flag = 0;//如果以后的循环不改变flag的值,说明没有发生数组元素的交换 //也就是说,这个数组已经排好序了。所有就可以提前退出循环。 if (arr[j] > arr[j + 1]) { flag = 1; temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } public static void main(String[] args) { int arr[] = {34, 67, 32, 19, 8, 20, 17, 44, 67, 80, 42, 57, 38}; BubbleSort.BubbleSort(arr); System.out.println("-----排序结果------"); for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); } } }
运行结果
-----排序结果------
8 17 19 20 32 34 38 42 44 57 67 67 80
Process finished with exit code 0
空间复杂度
空间复杂度是指算法在运行期间所需要的内存空间的数量级。
由于大部分算法的空间复杂度问题并不严重,并且算法的空间复杂度分析方法和算法的时间复杂度分析方法基本相同,所以一般只关注时间复杂度
static void reserse(int[] a,int[] b)
{
int n= a.length;
for(int i=0;i<n;i++)
{
b[i]=a[n-1-i];
}
}
当程序调用reserse(a,b)函数时,要分配的内存空间包括:引用a,引用b,局部变量n和局部变量i;因此
f(n)=c;其中c为常量。所以该算法的空间复杂度S(n)=O(1);
总结
算法的时间复杂度和两个因素有关:算法中的最大嵌套循环层数;最大嵌套循环结构中每次循环的次数。
一般来说,具有多项式时间复杂度的算法是可以接受的,具有指数时间复杂度的算法,只有当n足够小时才可以使用。一般效率较好的算法要控制在O(N)或者O(log2 N)