目录
一、算法的基本概念
1.1什么是算法
算法(Algorithm)是对特定问题求解步骤的一种描述,它是指令的有限序列,其中的每条指令表示一个或多个操作。
1.2算法的五个特性
1.有穷性:一个算法必须总在执行有穷步之后结束,且每一步都可在有穷时间内完成。(注意:算法必须是有穷的,但如果说是一个程序那么可以是无穷的)
2.确定性:算法中每条指令必须有确切的含义,对于相同的输入只能得出相同的输出。
3.可行性:算法中描述的操作都可以通过已经实现的基本运算执行有限次来实现。
4.输入:一个算法有零个或多个输入,这些输入取自于某个特定的对象的集合。
5.输出:一个算法有一个或多个输出,这些输出是与输入有着某种特定关系的量。
1.3“好”算法的特质
1)正确性。算法应能够正确地解决求解问题。
2)可读性。算法应具有良好的可读性,以帮助人们理解。
3)健壮性。输入非法数据时,算法能适当地做出反应或进行处理,而不会产生莫名其妙的输出结果。
4)高效率与低存储量需求
算法效率的度量:时间复杂度、空间复杂度
二、算法的时间复杂度
2.1时间复杂度
2.2时间复杂度的计算
int dizi(int n)
{
int fzd = 0;
for(int i = 0;i < n;i++)
{
for(int j = 0; j<n; j++)
{
fzd++;
}
}//有两层循环,每次循环n次
for(int k = 0; k<n; k++)
{
++fzd;
}//一层循环,循环n次
for(int l = 0;l<10;l++)
{
++fzd;
}//循环了10次
return dizi;
}
对于上述代码我们进行时间复杂度的计算:有两层for循环,每次循环n次+一层for循环,循环n次+循环10次。可以列出时间复杂度的表达式为n*n+n+10
当用大O表示法表示时,只代表是一种估算而非准确值(只保留阶数高的部分,常数项系数也可以忽略)。所以表达式就变为了O(n*n)
2.3技巧总结
2.4三种时间复杂度
三、算法的空间复杂度
3.1空间复杂度的计算
3.1.1普通程序
1)
//逐步递增
void dizi(int n){
int i=1;
while(i<=n){
i++; //每次都+1
printf("pandas don't play the flute %d\n",i);
}
printf("pandas really don't play the flute %d\n",n);
}
在此例当中,n为问题规模,但不管n的值怎么变化,在执行的过程当中它所需要的内存空间大小都是固定不变的一个常数值,所以算法的空间复杂度为 S(n)=O(1)
2)
void dizi(int n){
int flag[n]; //数组的长度为n
int i;
}
假设:一个int类型的变量占4个字节 那么存放int n则需要四个字节,而int flag[n]这个int型的数组 每一个数组元素都需要占4个字节,最后对于i这个变量占4个字节。所以该例所需要的内存空间为:4+4n+4=4n+8
空间复杂度与时间复杂度类似,我们在计算一个算法的空间复杂度时,只要关注它所需要消耗的空间是什么数量级的,什么阶数即可。所以同样用大O表示法来表示S(n)=O(4n+8)=O(n)
3.1.2递归程序
void dizi(int n){
int a,b,c; //局部变量的声明
//......
if(n>1){
dizi(n-1);
}
printf("pandas don't play the flute %d\n",n);
}
int main(){
dizi(5);
}
运行结果为:
pandas don't play the flute 1
pandas don't play the flute 2
pandas don't play the flute 3
pandas don't play the flute 4
pandas don't play the flute 5
每一级的函数调用都需要f个字节(f为常数) 当n=5时总共发生了5层递归调用。由此可知递归调用的层数与问题规模n是相等的。所以当问题规模为n时所需要的内存空间大小为f*n个字节。
用大O表示法只关注阶数可得空间复杂度为:S(n)=O(n)
空间复杂度=递归调用的深度
3.2技巧总结
由于个人知识和经验的局限性,文章中难免存在疏漏和不足之处,欢迎大家指正!