空间复杂度
任何程序的存储空间需求S(P)=c+Sp
c表示固定空间,通常包括指令空间等
Sp表示可变空间,其大小依赖具体要解决问题的特殊实例
e.g. 递归累加函数
float Rsum(float* a,const int n)
{
if(n==0)
return a[0];
else
return (Rsum(a,n-1)+a[n]);
}
每次调用Rsum,需要4个存储空间:a,n,返回值,返回地址
递归深度为n+1
所以空间复杂度为4(n+1)
时间复杂度
时间复杂度计算可以看所有程序步的总和,取其次数最高项(与n有关,并且去掉系数)
但是有时计算程序步总和比较复杂,所以我们可以看被重复最多次的程序,计算它的重复次数,取其次数最高项。(一般都是循环体最内层的程序)
e.g. for循环
void fun(int n)
{
int x=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
x++;
}
它的时间复杂度就看x++,重复n^2次,所以t=O(n^2)
e.g. 递归累加函数
float Rsum(float* a,const int n)
{
if(n==0)
return a[0];
else
return (Rsum(a,n-1)+a[n]);
}
t(0)=2 (if语句执行一次,return语句执行一次)
t(1)=2+2 (在t(0)基础上加上if语句一次,else中return语句一次)
……
所以,t(n)=2+t(n-1)
=2+2+t(n-2)
=……
=2n+2
所以时间复杂度为O(n)
e.g. 折半查找
int BinarySearch(int* a, int n, int t)
{
int left = 0;
int right = n - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (a[mid] == t)
return mid;
else if (a[mid] > t)
right = mid - 1;
else if(a[mid]<t)
left = mid + 1;
}
return left;
}
我们可以看到,这个方式是每查找一次,都缩小一半的范围,执行两个程序步
所以,2*2*2*……*2=n,重复次数就是logn,t=O(logn) (底数2省略)
e.g. 全排列生成器
void Permutations(char* a,const int k,const int m) //a代表字符数组,m代表元素个数-1(下标从0开始 )
{
if(k==m)
{
for(int i=0;i<=m;i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
}
else
{
for(int i=k;i<=m;i++)
{
swap(a[k],a[i]);
Permutations(a,k+1,m);
swap(a[k],a[i]);
}
}
}
我们可以看到,全排列生成器就是
每次都将第一个数与后面的数交换位置,得到新的序列, (第1次)
新的序列每次都将第二个数与后面的数交换位置 (第2次)
……
重复下去直到序列都将倒数第二位数与末位数交换位置 (第n次)
所以t=(n-1)!+(n-2)!+……
所以t=O(n*n!)
参考书籍:数据结构基础(C++)语言版 (第二版)
清华大学出版社