// 计算BubbleSort的空间复杂度?
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).
5. 复杂度分类
算法的复杂度有几个量级,表示如下:
O ( 1 ) < O ( l o g N ) < O ( N ) < O ( N l o g N ) < O ( N 2 ) < O ( 2 N ) < O ( N ! ) O(1) < O( log N) < O(N) < O(Nlog N) < O(N 2 ) < O(2^N) < O(N!) O(1)<O(logN)<O(N)<O(NlogN)<O(N2)<O(2N)<O(N!)
从左到右复杂度依次递增,算法的缺点也就越明显
图示如下:
5.1 常数O(1)阶
常数阶是一种非常快速的算法,但是在实际应用中非常难实现
以下是一种时间复杂度与空间复杂度皆为O(1)的算法:
c复制代码
int main()
{
int a = 0;
int b = 1;
int c = a + b;
printf("两数之和为%d\n", c);
return 9;
}
int binary_search(int nums[], int size, int target) //nums是数组,size是数组的大小,target是需要查找的值
{
int left = 0;
int right = size - 1; // 定义了target在左闭右闭的区间内,[left, right]
while (left <= right) { //当left == right时,区间[left, right]仍然有效
int middle = left + ((right - left) / 2);//等同于 (left + right) / 2,防止溢出
if (nums[middle] > target) {
right = middle - 1; //target在左区间,所以[left, middle - 1]
}
else if (nums[middle] < target) {
left = middle + 1; //target在右区间,所以[middle + 1, right]
}
else { //既不在左边,也不在右边,那就是找到答案了
printf("%d ", nums[middle]);
}
}
//没有找到目标值
return -1;
}
void func(int nums[], int size, int target)
{
for (int i = 0; i < size; i++)
{
binary_search(nums, size, target);
}
}
空间复杂度为O(NlogN)的算法,最常见的莫非归并排序
c复制代码
void Merge(int sourceArr[],int tempArr[], int startIndex, int midIndex, int endIndex){
int i = startIndex, j=midIndex+1, k = startIndex;
while(i!=midIndex+1 && j!=endIndex+1) {
if(sourceArr[i] > sourceArr[j])
tempArr[k++] = sourceArr[j++];
else
tempArr[k++] = sourceArr[i++];
}
while(i != midIndex+1)
tempArr[k++] = sourceArr[i++];
while(j != endIndex+1)
tempArr[k++] = sourceArr[j++];
for(i=startIndex; i<=endIndex; i++)
sourceArr[i] = tempArr[i];
}
//内部使用递归
void MergeSort(int sourceArr[], int tempArr[], int startIndex, int endIndex) {
int midIndex;
if(startIndex < endIndex) {
midIndex = startIndex + (endIndex-startIndex) / 2;//避免溢出int
MergeSort(sourceArr, tempArr, startIndex, midIndex);
MergeSort(sourceArr, tempArr, midIndex+1, endIndex);
Merge(sourceArr, tempArr, startIndex, midIndex, endIndex);
}
}
5.5 平方阶O(N2)
平方阶与线性对数阶相似,常见于嵌套循环中,每层循环的复杂度为O(N)
时间复杂度为O(N2),最常见的就是冒泡排序
c复制代码
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;
}
}
计算过程如下;
T ( N ) = 1 + 2 + 3 + . . . . . . + n − 1 = ( n 2 − n ) / 2 = O ( n 2 ) T(N)=1+2+3+......+n-1=(n^2-n)/2=O(n^2) T(N)=1+2+3+......+n−1=(n2−n)/2=O(n2)
空间复杂度为O(N2),最简单的就是动态开辟。
c复制代码
{
int n = 0;
int count = 0;
scanf("%d", &n);
int* p = (int*)malloc(sizeof(int) * n*n);
//开辟大小为n的空间
if (p == NULL)
{
perror("malloc fail");
return -1;
}
free(p);
p=NULL;
return 0;
}
5.6 指数阶O(2N)
指数阶的算法效率低,并不常用。
常见的时间复杂度为O(2N)的算法就是递归实现斐波拉契数列:
c复制代码
int Fib1(int n)
{
if (n == 1 || n == 2)
{
return 1;
}
else
{
return Fib1(n - 1) + Fib1(n - 2);
}
}
粗略估计
T ( n ) = 2 0 + 2 1 + 2 2 + . . . . . + 2 ( n − 1 ) = 2 n − 1 = O ( 2 N ) T(n)=2^0+2^1+2^2+.....+2^(n-1)=2^n-1=O(2^N) T(n)=20+21+22+.....+2(n−1)=2n−1=O(2N)