前言
参考书籍
- 数据结构C语言版(严蔚敏,李冬梅,吴伟民)
- 大话数据结构(程杰)
参考课程
算法与程序
- 算法是解决问题的一种方法或一个过程,考虑如何将输入转换成输出,一个问题可以有多种算法。
- 程序是用某种程序设计语言对算法的具体实现
算法的特性
- 有穷性:一个算法必须总是在执行有穷步之后结束,且每一步都在有穷时间内完成
- 确定性:算法中的每一条指令必须有确切的含义,没有二义性,在任何条件下,只有唯一的一条执行路径,及对于相同的输入只能得到相同的输出
- 可行性:算法是可执行的,算法描述的操作可以通过已经实现的基本操作执行有限次来实现
- 输入:一个算法有零个或多个输入
- 输出:一个算法有一个或多个输出
算法设计的要求
- 正确性
- 可读性
- 健壮性
- 高效性
算法效率
- 时间效率:算法所消耗的时间
- 空间效率:算法执行过程中所消耗的存储时间
时间效率和空间效率有时候是矛盾的
算法时间效率的度量
- 算法时间效率可以用一句算法编制的程序在计算机上执行所消耗的时间度量
两种度量方式
-
事后统计
- 将算法实现,测算其时间和空间开销
- 缺点:编写程序实现算法将花费较多的时间和精力;所得实验结果依赖于计算机的软硬件等环境因素,掩盖算法本身的优劣
-
事前分析
- 对算法所消耗资源的一种估算方法
事前分析方法
- 一个算法的运行时间是指一个算法在计算机上运行所消耗的时间大致可以等于计算机执行一种简单的操作(如赋值、比较、移动等)所需的时间与算法中进行的简单操作次数乘积
每条语句所执行一次所需要的时间,一般是随机器而异的。取决于机器的指令性能、速度以及编译的代码质量。是由机器本身的软硬件环境决定的,它与算法无关。
所以,我们可假设执行每条语句所需的时间均为单位时间。此时对算法的运行时间的讨论就可转化为讨论该算法中所有语句的执行次数,即频率之和了。
时间复杂度
for(i=1;i<=n;i++) //n+1次
for(j=1;j<=n;j++){ //n(n+1)次
c[i][j]=0; //n*n次
for(k=0;k<n;k++) //n*n*(n+1)次
c[i][j]=c[i][j]+a[i][k]+b[k][i]; //n*n*n次
}
推导大O阶的方法
- 用常数1取代运行时间中所有的加法常数
- 在修改后的运行次数函数中,只保留最高阶项
- 如果在最高阶项存在而不是1,则去掉与这个项相乘的常数。
得到的结果就是大O阶!
举例
int sum=0,n=100; //执行1次
sun=(1+n)*n/2; //执行1次
printf("%d",sum); //执行1次
这个算法的运行次数函数是f(3)。根据大O阶推导方法,第一步将3改为1。在保留最高阶项时发现,根本没有最高阶项,所以这个算法的时间复杂度为O(1).
for(int i=0;i<n;i++)
{
for(int j=i;j<n;j++)
{
//时间复杂度为O(1)的程序步骤序列
}
}
这个函数的执行次数为(n^2+n)/2.
根据推导公式
- 没有加法常数不考虑
- 只保留最高阶,所以只保留n^2 / 2;
- 去除与这项相乘的常数,也就是去掉1 / 2;
故时间复杂度为O(n^2)
空间复杂度
- 算法的空间复杂度通过计算算法所需的存储空间实现,即运行完一个程序所需内存的大小
- 算法的时间复杂度和空间复杂度是可以相互转化的
举例
数组逆序
算法1
for(int i=0;i<n/2;i++)
{
t=a[i];
a[i]=a[n-i-1];
a[n-i-1]=t;
}
算法2
for(int i=0;i<n;i++)
b[i]=a[n-i-1];
for(int i=0;i<n;i++)
a[i]=b[i];
对于算法1,仅需要另外一个变量t,与问题规模n大小无关,所以空间复杂度为O(1)
对于算法2,需要借助另一个大小为n的辅助数组b,所以空间复杂度为O(n)
后记
关于更加详细的时间复杂度与空间复杂度的解释,可以参考http://t.zoukankan.com/LiuYanYGZ-p-12232774.html
https://blog.csdn.net/swadian2008/article/details/105073428
https://blog.csdn.net/jsjwk/article/details/84315770