一. 时间复杂度
时间复杂度实际就是一个函数,该函数计算的是执行基本操作的次
数,而不是程序执行时间。
1.在实际中通常关注的是算法的最坏运行情况。
一个算法的最坏情况的运行时间是在任意输入下的运行时间上界。
一般情况下使用O渐进表示法来计算算法的时间复杂度。
2.书写方式:
- 用常数1取代运行时间中的所有加法常数
- 在修改后的运行次数函数中,只保留最高阶项
- 如果最高阶项系数存在且不是1,则去除与这个项相乘的常数
- 递归算法时间复杂度:递归总次数*每次递归次数。
例1:
void Test(int n)
{
int iConut = 0;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
iCount++;
}
}
for (int k = 0; k < 2 * n; ++k)
{
iCount++;
}
int count = 10;
while (count--)
{
iCount++;
}
}
语句总执行次数:f(n) = n^2+2*n+10;
时间复杂度为O(n)=n^2;
例2:
void Test4(int m, int n)
{
int iCount = 0;
for (int i = 0; i < 2 * m; ++i)
{
for (int j = 0; j < n; ++j)
{
iCount++;
}
}
}
f(n,m) = 2*m*n
O(N)=O(m*n);
例3:
void Test(int n)
{
int iCount = 0;
for (int iIdx = 0; iIdx < 10; ++iIdx)
{
iCount++;
}
}
f(n)=10; O(n)=O(1);
例4:
int factorial(int n)//求n的阶乘,递归法
{
if(n<=1)
return 1;
else
{
return n*factorial(n-1);
}
}
O(n)=n
常用的有7种:时间复杂度依次增加:
O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^3)<O(2^n)
二. 空间复杂度
不是计算实际占用的空间,而是计算整个算法的辅助空间单元个数,及所创建的变量个数。
递归算法的空间复杂度=递归深度*每次递归所需的辅助空间。
int Sum(int N)
{
int count = 0;
for (int i = 1; i <= N; ++i)
count += i;
return count;
}
空间复杂度:O(1);
三.实例解析
a.二分查找算法
非递归(迭代)
int binary_search(int *arr, int sz, int n)
{
int left = 0;
int right = sz - 1;
while (left <= right)
{
int mid = (left + right)/2;
if (arr[mid] > n)
{
right = mid - 1;
}
else if (arr[mid] < n)
{
left = mid + 1;
}
else
return mid;
}
return -1;
}
时间复杂度为:O(logn)
空间复杂度为:O(1);//创建了临时变量mid
递归
int binary_search(int *arr, int left, int right, int n)
{
assert(arr);
if (left <=right)
{
int mid = (left + right) / 2;
if (arr[mid] < n)
{
return binary_search(arr, mid + 1, right, n);
}
else if (arr[mid]>n)
{
return binary_search(arr, left, mid - 1, n);
}
else
return mid;
}
else
return -1;
}
每次对半查找(类似折纸)
时间复杂度: O(logn)
空间复杂度:O(logn)
b.斐波那契数列
递归:
long long Fib(int n)
{
if (n < 3)
return 1;
return Fib(n - 1) + Fib(n - 2);
}
时间复杂度O(2^n)
空间复杂度O(n)
图解过程:
非递归:
int Fib(int n)
{
int a = 1;
int b = 1;
int c = 1;
if (n<2)
{
return n;
}
while (n>2)
{
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
时间复杂度:O(n)
空间复杂度:O(1)