复杂度初步理解

1.时间复杂度

时间复杂度本身是个函数,方法很多,这里主要使用大O渐进法

O()

void Func1(int N)
{
int count = 0;
for (int i = 0; i < N ; ++ i)
{
for (int j = 0; j < N ; ++ j)
{
++count;
}
}

for (int k = 0; k < 2 * N ; ++ k)
{
++count;
}
int M = 10;
while (M--)
{
++count;
}
}

这里我们就能用O(N*N)来表示时间复杂度。

这里首先要注意,我们只取对运转次数影响最大的那一项,其他的项在无穷增长中,差距会越来越小,我们要的是估算,而不是准确值。

void Func1(int N)
{
int count = 0;
for (int i = 0; i < N ; ++ i)
{
for (int j = 0; j < N ; ++ j)
{
++count;
}
}

for (int k = 0; k < 2 * N ; ++ k)
{
++count;
}
int M = 10;
while (M--)
{
++count;

这里要注意的是,如果运行次数是一个清晰的常数,不管多大,都用1表示,也就是O(1)

,对于cpu来说,你运行一次还是1一亿次,对于现在越发快速的cpu来说,都是很短的时间。

时间复杂度是一个保守的估算,有些函数的运行次数取决于实际存储,比如一个查找函数,我们运行多少次,取决于实际的存储中到底有没有存储,存储在哪个位置。这种情况下,我们就可以看到这种函数有最好(马上找到)、平均(比如数组遍历到一半)、最坏(比如数据遍历到最后),为了保守估算,我们一般用最坏的情况作为这个函数的时间复杂度。

假如最高项的系数不是1呢,那么我们就除去这个系数(常数),得到的才是我们的复杂度。

但要注意,我们算时间复杂度,是先有思想(比如冒泡、快排),然后根据思想来估算,而不是写出代码后,数循环次数。

对于递归函数,我们是进行累加,而非累乘,因为我们估算的是运算的次数,而非运算的大小

// 计算阶乘递归Fac的时间复杂度?
long long Fac(size_t N)
{
 if(0 == N)
 return 1;
 
 return Fac(N-1)*N;
}

这样的函数,不要被*迷惑,我们计算运算次数,而非大小



如果函数里面有个长度为N的for循坏,
这里与上面有所不同,因为每次调用函数,都会进行一次循环,而又是等差数列
所以可以用等差求和来算,最后省去系数,就剩N^2
long long Fib(size_t N)
{
 if(N < 3)
 return 1;
 
 return Fib(N-1) + Fib(N-2);
}



fib的思想,可以理解为等比数列,而这里N<3,所以最后是2^(N-2)次
而利用等比数列求和,最后的时间复杂度,通过递归累加,是2^N

2.空间复杂度

空间复杂度是对算法在运行过程中临时占用空间大小的量度,不计算byte,而是变量的个数,也用大O渐进表示法。

函数运行时所需要的栈空间在编译时就已经确定了,因此主要算的是函数在运行时运行的额外的空间来确定。

void BubbleSort(int* a, int n)
{
 assert(a);
 for (size_t end = n; end > 0; --end)
 {
 int exchange = 0;
 for (size_t i = 1; i < end; ++i)
 {
 if (a[i-1] > a[i])
 {
 Swap(&a[i-1], &a[i]);
 exchange = 1;
 }
 }
 if (exchange == 0)
 break;
 }
}

这里看似用了很多额外的变量,但是,这都是有限的,明确的,常数个变量,那么就只是O(1)
long long* Fibonacci(size_t n)
{
 if(n==0)
 return NULL;
 
 long long * fibArray = (long long *)malloc((n+1) * sizeof(long long));
 fibArray[0] = 0;
 fibArray[1] = 1;
 for (int i = 2; i <= n ; ++i)
 {
 fibArray[i] = fibArray[i - 1] + fibArray [i - 2];
 }
 return fibArray;
}

这里我们要关注的动态内存部分,其他的额外变量都只是常数,可以直接忽略
动态内存会额外申请n+1大小的数组,因此,每个元素算一个变量的话,那就是n+1个变量,
由于空间复杂度,我们也是估算,所以直接O(N)即可

递归空间复杂度也是累加,但空间存在重复利用的情况

// 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{
 if(N == 0)
 return 1;
 
 return Fac(N-1)*N;
}

这里很简单,每次调用函数都会开辟一个栈空间,所以就是O(N)



long long* Fibonacci(size_t n)
{
 if(n==0)
 return NULL;
 
 long long * fibArray = (long long *)malloc((n+1) * sizeof(long long));
 fibArray[0] = 0;
 fibArray[1] = 1;
 for (int i = 2; i <= n ; ++i)
 {
 fibArray[i] = fibArray[i - 1] + fibArray [i - 2];
 }
 return fibArray;
}
这里就不一样了,fib的思想,看起来会开辟很多空间,好像要开辟2^N个空间,但事实上,
空间是重复利用的,最多只需要N-1个空间即可,因为递归的调用,是先一撸到底,然后再去其他分支
这样被算好了的空间,就可以拿来给别的分支用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值