时间复杂度、空间复杂度我之前从来没有了解过,他们是什么,有什么作用呢?? 最近偶然的机会看算法遇到了这两个东西,所以就简单的来了解一下,以下纯属个人理解,有问题欢迎指出~~
那么什么是时间复杂度,什么是空间复杂度呢??
- 时间复杂度:一个算法的执行时间根据数据规模增加的一个趋势。
- 空间复杂度:占用内存的趋势。
T(n) = O(f(n))
S(n) = O(f(n))
这个叫做大O表示法,表示随着输入的值变化,程序运行所需要的时间与输入值的变化关系。
T表示算法需要执行的总时间
S表示算法需要的总空间
fn表示代码执行的总次数
时间复杂度、空间复杂度对于我们的工作有什么帮助呢??
- 对于不同的数据规模,能够决策采用不同的解决方案。
- 了解什么情况下用暴力解法就能够解决问题,避免写复杂的代码。
- 在写代码之前,就能够预估程序的运行时间,从而可以知道是否能够满足产品需求。
- 在程序出现性能瓶颈时,能够有解决方案而不是抓瞎。
时间复杂度,空间复杂度是怎么计算的??
通过代码能够更好的来了解:
function go(n) {
var item = 0; // 执行1次
for (var i=0; i<n; i++) { // 执行n次
for (var j=0; j<n; j++) { // 执行n*n次
item = item+i+j; // 执行n*n次
}
}
return item; // 执行1次
}
// 所以以上的T(n) = O(f(1+n+n*n*2+1))) = O(f(2+n+2n²)))
/*
时间复杂度看的是代码执行时间的一个趋势,所以说在于n,当数据量特别大的时候,那些常量起不到决定性的作用,常常被忽略掉。这里只看大量级的循环就行,所以这个代码的时间复杂度为:T(n) = O(n²)
*/
几种常见的时间复杂度:
这段代码的执行时间完全由N来控制,所以说 T(n) = O(n)
for(var i=0; i<n; i++) {
sum += i;
}
这段函数不受任何参数影响,代码走一遍就完事,这种的代码用T(n) = O(1) 表示
function total() {
console.log(1);
}
在下面的代码种第二段代码里边调用了第一段代码,所以说在这个代码里边是 go: (1+n)
在main函数里边的时候是(1+n*go)=(1+n+n*n)
所以最后的时间复杂度是T(n) = O(n²)
一个函数在另一个函数里边被调用,这种情况是把两个函数的时间复杂度相乘。
function go(i) {
var sum = 0;
for (var j = 0; j < i; j++) {
sum += i;
}
return sum;
}
function main(n) {
var res = 0;
for (var i = 0; i < n; i++) {
res = res + go(i); // 这里是重点
}
}
还有另外一种情况,就是说在一个函数里边有多块代码,但是并没有被相互调用,那么这种情况的时候,我们只需要取复杂度最大的代码块就可以了下边这块代码中,第一块代码有两层循环,通过上边的例子我们已经得知复杂度是n²+n。
那么在这种情况的时候,当N接近无限大的时候N是对n²起不到决定性作用的,所以下边这块代码的时间复杂度就是取最大值的n²
function go(n) {
for (var i = 0; i < n; i++) {
for (var j = 0; j < n; j++) {
console.log(1)
}
}
for (var i = 0; i < n; i++) {
console.log(2)
}
}
在这段代码中,可以看到while里边,作为判断条件的i被每次*10,那么所以说最后循环的次数并不是n次,而是说十分之一n次,所以说这个时候的时间复杂度是10i=n,所以得出结论就是时间复杂度是T(n)=O(logn)
function log(n) {
var i = 1;
while (i <= n) {
i = i * 10;
}
}
这段代码里边一个函数里边有两个循环,但是形参有两个,我们现在无法得知n和m到底谁大谁小,所以说这个时候代码的时间复杂度是O(m+n)
function go(m,n) {
for (var i = 0; i < n; i++) {
console.log(1)
}
for (var i = 0; i < m; i++) {
console.log(2)
}
}
空间复杂度和时间复杂度差不多,几种常见的空间复杂度有:
O(1)
let a = 1;
let b = 1;
let c = 1;
O(n)
/*
代码中创建了一个n长度的数组,很明显数组的长度根据n来决定,所以空间复杂度为n
这里没有用循环,是因为只要不是在循环里边不停的声明变量,只改变值的话是不会层架空间复杂度的
*/
let arr = Array(n);
O(n²)
let arr = [];
for (var i=0; i<n; i++) {
arr[i] = i;
for (var j=0; j<n; j++) {
arr[i][j] = j;
}
}
几种排序的时间复杂度和空间复杂度
排序类型 | 时间复杂度 | 空间复杂度 | 是否稳定 |
冒泡排序 | 最好O(n) 最坏O(n²) 平均O(n²) | O(1) | 是 |
快速排序 | 最好O(nlogn) 最坏O(n2) 平均O(nlogn) | 最好O(logn) 最差O(n) | 否 |
插入排序 | 最好O(n) 最坏O(n²) 平均O(n²) | O(1) | 是 |
希尔排序 | 最好O(nlog²n) 最坏O(nlog²n) 平均O(nlogn) | O(1) | 否 |
选择排序 | O(n²) | O(1) | 否,因为会遇到重复的值 |
归并排序 | 最好O(nlogn) 最坏O(nlogn) 平均O(nlogn) | O(n) | 是 |