1.时间复杂度
算法的时间复杂度是一个函数,指的是算法的基本操作执行的次数。
即:找到某条基本语句与问题规模N之间的数学表达式,得到的N的函数就是时间复杂度
例1:
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;
}
printf("%d\n", count);
}
可以算出count = N^2+2*N+10;
采用大O渐进表示法后Func1的时间复杂度位O(N^2)
大O渐进表示法的规则:
1.用常数1取代所有项中的常数项
2.修改后的只保留最高阶项
3.如果最高阶项存在且不是1,则去掉该项的系数,得到的结果就是大O阶
另外,在实际情况 中一般关注的是算法运行的最坏情况
例2:
void Func2(int N)
{
int i = 0;
int count = 0;
for (i = 0; i <2 * N; i++)
{
count++;
}
int M = 10;
for (i = 0; i < M; i++)
{
count++;
}
printf("%d\n", count);
}
F(N) = 2 *N +10,通过大O阶推导可得时间复杂度位O(N).
例3:
void Func3(int N, int M)
{
int k = 0;
int count = 0;
for (k = 0; k < N; k++)
{
count++;
}
for (k = 0; k < M; k++)
{
count++;
}
printf("%d\n", count);
}
F(N,M) = N+M,时间复杂度为N+M;
例4:
void Func4(int N)
{
int i = 0;
int count = 0;
for (i = 0; i < 100; i++)
{
count++;
}
printf("%d\n", count);
}
F(N) = 100, 时间复杂度为O(1);
例5:
const char* strchr(const char* str, int character)
{
assert(str);
char* ret = str;
while (*ret)
{
if (*ret == character)
return ret;
ret++;
}
return NULL;
}
算法最坏的情况就是字符串最后一个字符是要找的字符,那么时间复杂度为O(N)
例6:
void BubbleSort(int* arr, int n)
{
assert(arr);
int i = 0;
int j = 0;
int flag = 0;
for (i = 0; i < n; i++)
{
for (j = 0; j < n - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
int tem = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tem;
flag = 1;
}
}
if (flag == 0)
break;
}
}
最好的情况是数组有序,只运行了N次,最坏的情况是运行了(N*(N+1))/2,因此时间复杂度为O(N^2).
例7:
long long Fac(size_t N)
{
if (0 == N)
return 1;
return Fac(N - 1) * N;
}
Fac(N)->Fac(N-1)->Fac(N-2)->....->Fac(1),调用N次,因此时间复杂度为O(N)
例8:
long long Fib(size_t N)
{
if (N < 3)
return 1;
return Fib(N - 1) + Fib(N - 2);
}
Fib(N).........................................1
Fib(N - 1) + Fib(N - 2) ............................1*2
Fib(N - 2) + Fib(N - 3) Fib(N - 3) + Fib(N - 4).........1*2*2
Fib(N - 3) + Fib(N - 4)Fib(N - 4) + Fib(N - 5) Fib(N - 4) + Fib(N - 5) Fib(N - 5) + Fib(N - 6)...1*2*2*2
因此时间复杂度为O(2^N)
2. 空间复杂度
空间复杂度是对一个算法在运行过程中临时占用储存空间大小的度量。
注意:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时显示申请的额外空间来确定。
例1:
void BubbleSort(int* arr, int n)
{
assert(arr);
int i = 0;
int j = 0;
int flag = 0;
for (i = 0; i < n; i++)
{
for (j = 0; j < n - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
int tem = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tem;
flag = 1;
}
}
if (flag == 0)
break;
}
}
只额外申请了一个i,j,flag,tem 常数个临时变量的空间,因此空间复杂度为O(1)
例2:
long long* Fib(size_t N)
{
if (N == 0)
return NULL;
long long* FibArr = (long long*)malloc((N + 1) * sizeof(long long));
FibArr[0] = 0;
FibArr[1] = 1;
for (int i = 2; i < N; i++)
{
FibArr[i] = FibArr[i - 1] + FibArr[i - 2];
}
return FibArr;
}
函数额外申请了N+1个long long的空间,因此空间复杂度为O(N)
例3:
long long Fac(size_t N)
{
if (0 == N)
return 1;
return Fac(N - 1) * N;
}
开辟了N个栈帧,每个栈帧使用常数个变量,空间复杂度为O(N)
例4:
long long Fib(size_t N)
{
if (N < 3)
return 1;
return Fib(N - 1) + Fib(N - 2);
}
Fib(N)调用 Fib(N - 1) + Fib(N - 2),是先为Fib(N - 1),返回结果后,空间归还给系统,然后再为Fib(N - 2)开辟栈帧,实际上Fib(N - 1)和Fib(N - 2)使用的是同一个栈帧,因此只需要开辟N-1个栈帧,空间复杂度为O(N)
完结,撒花!!!🌸🌸🌸