详解时间复杂度+空间复杂度+各种代码案例

算法效率分析分为两种:第一种是时间效率,第二种是空间效率。时间效率被称为时间复杂度,而空间效率被称作空间复杂度。 时间复杂度主要衡量的是一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额外空间。

在计算机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。

在看了上述概念之后,大家应该都对时间复杂度和空间复杂度有了一定的认识,那么时间复杂度和空间复杂度具体应该怎么计算呢,那咱们话不多说,直接上代码。

一.时间复杂度

大O的渐进表示法

算法中的基本操作的执行次数,为算法的时间复杂度(注意:这里指的是最坏情况下)
在表示时间复杂度时,我们统一使用大O渐近法,实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数。

推导大O阶方法

1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶

案例一:冒泡排序

void bubbleSort(int[] array) {
for (int end = array.length; end > 0; end--) {
boolean sorted = true;
for (int i = 1; i < end; i++) {
	if (array[i - 1] > array[i]) {
	Swap(array, i - 1, i);
	sorted = false;
	}
}
if (sorted == true) {
		break;
		}
	}
}

这里我们把需要进行冒泡排序的元素个数看作n,最外层的for循环每执行一次,n的值减一,在第一次执行外层for循环时,end = n,那么内层for循环就需要执行n-1次,以此类推,当代码执行结束,代码基本操作执行的总次数就为(n-1)+ (n-2) + (n-3) + ··· + 1,利用等差数列的求和公式不难算出结果为(n-1)*n/2,所以最后冒泡排序的时间复杂度为O(n^2),那么最好情况下的时间复杂度是多少呢?最好情况下:O(1) ,这时序列是有序的,只需要遍历一遍序列。

案例二:二分查找

int binarySearch(int[] array, int value) {
int begin = 0;
int end = array.length - 1;
while (begin <= end) {
	int mid = begin + ((end-begin) / 2);
	if (array[mid] < value)
		begin = mid + 1;
	else if (array[mid] > value)
		end = mid - 1;
	else
		return mid;
		}
	return -1;
}

二分查找可以看成每次查找元素的一半,每查找一次,数据就减半,我们把n作为总长度,x为次数,通过下面的图我们可以发现一条规律:n/2^x = 1 ,所以x = log2^n,最后,二分查找的时间复杂度为O(logN)

在这里插入图片描述

案例三:普通递归

long factorial(int N) {
return N < 2 ? N : factorial(N-1) * N;
}

通过分析代码,我们可以发现递归的时间复杂度是:递归的次数 * 每次递归后代码的执行次数。
在执行递归时,当N大于等于2时,会调用factorial(N-1),基本操作递归了N次,普通递归的时间复杂度为O(N)。

案例四:斐波那契数列

int fibonacci(int N) {
return N < 2 ? N : fibonacci(N-1)+fibonacci(N-2);
}

通过分析代码,我们可以发现在执行递归时,当N大于等于2时,会调用fibonacci(N-1)和fibonacci(N-2),并且按照这种规律递归下去,当我们把所有的基本执行操作加起来时,可以发现这是一个等比数列求和,总次数为2^0 + 2^1 + 2^2 +……+2^(N-1), 经过数学计算可以得到斐波那契数列的时间复杂度为O(n^2)。
在这里插入图片描述

二.空间复杂度

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度 。空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法。

案例一:冒泡排序

void bubbleSort(int[] array) {
for (int end = array.length; end > 0; end--) {
boolean sorted = true;
for (int i = 1; i < end; i++) {
	if (array[i - 1] > array[i]) {
	Swap(array, i - 1, i);
	sorted = false;
	}
}
if (sorted == true) {
		break;
		}
	}
}

在上面这段代码执行时,需要临时开辟出空间来存储变量sorted,所以冒泡排序的空间复杂度为O(1)。

案例二:普通递归

long factorial(int N) {
return N < 2 ? N : factorial(N-1) * N;
}

在执行递归时,当N大于等于2时,会调用factorial(N-1),需要开辟的临时空间为N,普通递归的空间复杂度为O(N)。

案例三:斐波那契数列

int fibonacci(int N) {
return N < 2 ? N : fibonacci(N-1)+fibonacci(N-2);
}

如下图所示,下图展示了递归栈帧的二叉树,当递归到每一棵树的右子树时,左子树已经算完了,栈帧已经回收了,递归调用了N次,开辟了N个栈帧,每个栈帧使用了常数个空间,所以斐波那契数列的空间复杂度为O(N)。
在这里插入图片描述

三.总结:常见复杂度大小排序

常见的复杂度从小变大排序:
O(1) < O(logn) < O(n) < O(nlogn) < O(n^2)

  • 13
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值