算法分析(时间复杂度和空间复杂度)
对于一个给定的算法需要做两项分析,第一就是证明算法的正确性,第二就是计算算法的复杂度。算法的复杂度包括时间复杂度和空间复杂度。

1  度量算法效率的方法
共存在两种方法:事后统计法和事前分析估计算法。

事后统计法:先将算法实现,然后输入适当的数据运行,计算算法的时间复杂度和空间复杂度。

事前分析估算法(渐进复杂度):对算法所消耗资源的一种估算方法。比较常用。

本文主要是渐进复杂度的解释。

2  算法的时间复杂度
影响算法时间复杂度的主要因素是问题规模。

问题规模:是指输入量的多少。规模大的输入量需要的运行时间更长。所以运行算法所需要的时间T的问题是问题规模n的函数,记作T(n)。

为了客观的表示一个算法的运行时间,可以用基本语句的执行次数来度量算法的工作量。

定义:一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。

通常采用大O记号表示。

时间复杂度分析的基本策略是:从内向外分析,从最深层开始分析。如果遇到函数调用,要深入函数进行分析。

3  求解时间复杂度的步骤
(1)找出算法的基本语句,一般是循环体。

(2)计算基本语句执行次数的数量级,也就是基本语句执行次数函数的最高次幂。可忽略低次幂和系数。

(3)用大O记号表示时间复杂度。

4  计算时间复杂度常用性质
(1)一些简单的输入输出赋值语句,近似为O(1)。

(2)对于顺序结构需要求和法则。

求和法则:若T1(n)=O(f(n))、 T2(n)=O(g(n)),则 T1(n)+T2(n)=O(max(f(n), g(n)))。

(3)对于选择结构(if判断),需要看执行语句。

(4)对于循环结构采用乘法法则。

乘法法则:若T1(n)=O(f(n))、 T2(n)=O(g(n)),则 T1*T2=O(f(n)*g(n))。

如果算法中包含嵌套的循环,则基本语句通常是最内层的循环体,如果算法中包含并列的循环,则将并列循环的时间复杂度相加。

5  常用时间复杂度示例
常见的时间复杂度有:常数阶O(1),对数阶O(log2n),线性阶O(n), 线性对数阶O(nlog2n),平方阶O(n2),立方阶O(n3)。由小到大依次为:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<Ο(2n)<Ο(n!)。

(1)Ο(log2n)(二分查表)

decimal Factorial(int n)

{

if (n == 0)

return 1;

else

return n * Factorial(n - 1);

}

(2)O(n)(一次for循环)

decimal Factorial(int n)

{

if (n == 0)

return 1;

else

return n * Factorial(n - 1);

}

(3)Ο(nlog2n)(快排)

void quickSort(int arr[], int left, int right)  
{
if (left < right)
{
int key = arr[left];
int i = left, j = right;
while (i < j)
{
while (arr[j] > key && j > i)
j--;
if (i < j)
arr[i++] = arr[j];
while (arr[i] < key && i < j)
i++;
if (i < j)
arr[j--] = arr[i];
}
arr[i] = key;
quickSort(arr, left, i - 1);
quickSort(arr, i + 1, right);
}
}

(4)O(n2)(冒泡排序)

void BubbleSort(int arr[],int num)
{
int i,j;
int temp=0;
for(i=0;i<num-1;i++)
{
for(j=0;j<num-i-1;j++)
{
if(arr[j]>arr[j+1])
{
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}

6  算法的空间复杂度

空间复杂度定义了为算法所消耗的存储空间。是算法运行是所占用存储空间大小的量度。