复杂度也叫渐进复杂度,包括时间复杂度和空间复杂度,用来分析算法执行效率与数据规模之间的增加关系。c++
复杂度分析能够在初期帮助程序员预估该程序的性能耗费。程序员
时间复杂度用于表示算法的时间耗费与数据规模增加之间的关系算法
空间复杂度用于表示算法的存储空间与数据规模增加之间的关系数组
总复杂度等于量级最大的那段代码的复杂度,好比说一个程序中存在两段不一样时间复杂度的代码块:bash
int f(int n) {
int sum = 0;
for (int i = 0; i < n; ++i) {
sum ++;
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
sum ++;
}
}
return sum;
}
复制代码
第一个for循环的时间复杂度T1,和第二个嵌套for循环的时间复杂度T2分别为:函数
那么整个程序的时间复杂度为:性能
若是量级大的代码块有多个,而咱们没法事先评估谁的量级大,就不能简单地省略其中一个,例如:ui
int f(int n, int m) {
int sum = 0;
for (int i = 0; i < n; ++i) {
sum ++;
}
for (int i = 0; i < m; ++i) {
sum ++;
}
return sum;
}
复制代码
该函数的时间复杂度为:spa
乘法法则: 嵌套代码的复杂度等于嵌套内外代码复杂度的乘积,例如:code
int f(int n, int m) {
int sum = 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
sum += j;
}
}
return sum;
}
复制代码
该函数的时间复杂度为:
对于常量复杂度而言,执行时间不随 n 的增大而增加的代码,咱们都记做 O(1) 。 通常状况下,只要算法中不存在循环语句、递归语句,即便有成千上万行的代码,其时间复杂度也是Ο(1)
对于对数阶复杂度而言, 无论是以 2 为底、以 3 为底,仍是以 10 为底,咱们能够把全部对数阶的时间复杂度都记为O(logn)
对于指数阶、阶乘阶复杂度而言, 当数据规模 n 增大,算法的执行时间会急剧增长 ,所以这两类时间复杂度的算法是很是低效的算法不推荐使用
上述状况是程序必须执行完全部代码得出的时间复杂度。而在不少状况下,咱们不须要进行完整的遍历或递归,例如查找一个数组中是否存在5:
int val[n];
bool find() {
for (int i = 0; i < n; i++) {
if (val[i] == 5) {
return true;
}
}
return false;
}
复制代码
最好状况时间复杂度是最理想状况下执行这段代码的时间复杂度,体如今上述代码中,就是数组第一个元素是5,所以最好状况时间复杂度为O(1)
最坏状况时间复杂度是最糟糕状况下执行这段代码的时间复杂度 ,体如今上述代码中,就是数组中不存在元素5,所以最坏状况时间复杂度为O(n)
平均状况时间复杂度是考虑全部可能发生的状况、几率、以及对应耗费的时间,而后取平均值,体如今上述代码中,就是考虑n+1种状况(5出如今0~n-1位置 和 5没有出现)及其几率、对应耗费的时间,获得:
因为时间复杂度能够省略掉系数、低阶、常量,把这个公式简化以后获得的平均时间复杂度就是 O(n)
规则与时间复杂度的三点相似,再也不赘述
咱们能够经过空间复杂度,来预估程序所耗费的内存。好比:
const int N = 1000000;
int[] val = new int[N];
复制代码
int型占四字节,对于O(n)空间复杂度的程序来讲,当n为1e6时,耗费的内存为:
比较常见的空间复杂度有:
相比时间复杂度, O(logn)、O(nlogn)
等对数阶复杂度平时几乎用不到~