复杂度定义
算法的开销主要从它所占用的「时间」和「空间」两个维度去考量。
- 时间维度:是指执行当前算法所消耗的时间,我们通常用「时间复杂度」来描述。
- 空间维度:是指执行当前算法需要占用多少内存空间,我们通常用「空间复杂度」来描述。
算法的效率主要通过其时间复杂度和空间复杂度来评估,然而,在两者之间往往很难取得共存。 对于两者而言,我们往往需要寻找一个最优点进行平衡
时间复杂度
寻求一个算法的「时间复杂度」,首先需要了解「 大O符号表示法 」,即 T(n) = O(f(n))。
在 大O符号表示法中,时间复杂度的公式是: T(n) = O( f(n) ),其中f(n) 表示每行代码执行次数之和,而 O 表示正比例关系,这个公式的全称是:算法的渐进时间复杂度。
在常用算法中,只要不涉及循环,都是常数阶O(1),较常见的算法复杂度有
- 常数阶O(1)
- 对数阶O(logN)
- 线性阶O(n)
- 线性对数阶O(nlogN)
- 平方阶O(n²)
- 立方阶O(n³)
- K次方阶O(n^k)
- 指数阶(2^n)
常数阶:声明常量,不涉及循环
let num = 1
var add = (num) => {
return num + 1
}
对数阶O(logN): 循环的递增为*2,则为logN
let len = 20;
for(var i=1;i<len;i=i*2) {
console.log(i)
}
线性阶O(n):普通循环,包括for,forEach,map等
let arr = [1,2,3,4,5,6]
for(let i=0;i<arr.length;i++){
console.log(arr[i])
}
平方阶O(n²)及立方阶以后: 冒泡排序等,多个循环嵌套
// 嵌套循环从头至尾,时间复杂度O(n²),嵌套三层为立方阶O(n³)
const arr = [1, 23, 2, 9, 5, 9, 3, 5, 7]
const arraySort = (arr) => {
if (arr.length < 2) {
return arr
}
let temp = 0
for (let i = 0; i < arr.length; i++) {
for (let j = i; j < arr.length; j++) {
if (arr[i] > arr[j]) {
temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
}
}
}
return arr
}
arraySort(arr)
空间复杂度
寻求一个算法的空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度,记做S(n)=O(f(n))。。
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的一个量度,同样反映的是一个趋势,我们用 S(n) 来定义。
平方阶S(1): 没有分配新的新的空间,重复利用同一空间进行算法计算
// 每次i的递增都是对于原空间进行新的赋值,没有开辟新的空间,空间复杂度S(1)
for (var i = 0; i < n; i++) {
console.log(i)
}
平方阶S(n): 每次数组赋值都会申请一个空间存储变量,所以此函数的空间复杂度为 O(n)。
// 每次循环会开辟一个新的空间,时间复杂度S(n)
const initArr = (n) => {
var arr = []
for (var i = 0; i < n; i++) {
arr[i] = i
}
return arr
}