数据结构慢慢啃(step 3)

435 阅读2分钟

衡量一个算法的好坏, 从时间复杂度和空间复杂度来全面分析,
算法的最优解: 先考虑时间复杂度再考虑空间复杂度

BigO表达式
BigO表达式

时间复杂度

常数阶O(1) : 算法的执行时间总是为常数, 不随数据量变化而改变

int k = i + j;

线性阶O(n) : 算法的执行时间随数据量的变化线性增长

for (int i = 0; i < n; i++) {
    //TODO
}

平方阶O(n^2) :

for(int i = 1; i <= n; i++) {
   for(int j = 1; j <= n; j++) {
      //TODO
   }
}

对数阶O(logn) : 2^x = n 得出 x = log₂n, while循环处理不一定都是线性的

int i = 1;
while (i < n) {
    i = i * 2;
}

PS: N^M 就是 N * N * N ....(M个N相乘, 感觉都把数学内容都还给老师了)

线性对数阶O(n * logn) : 把时间复杂度为logn代码循环n遍

for(int m = 1; m < n; m++) {
    i = 1;
    while(i < n) {
        i = i * 2;
    }
}

空间复杂度

常数阶O(1) :

int i = 1;
int j = 2;
int m = i + j;

线性阶O(n) :

int[] m = new int[n]
for(int i = 1; i <= n; ++i) {
   int j = i;
   j++;
}

判断O(logn)

// 该时间复杂度判定方式
// n经过几次"除以m"操作后, 等于1? 
// 1经过几次"乘以m"操作后, 等于n?
while(n) {
  n /= 10;
}

何种情况下, 选择合适的算法

根据数据的规模来判定, 使用何种算法, 并不能简单通过时间复杂度来区分. 规模越大, 通过时间复杂度判定是越准确的. 这也是为啥? Arrays.sort(), 再数据量小的时候反而使用插入算法O(n^2)
ps:特别注意的是计算时间复杂度的变量
O(k ^ 2 + nlogn + m) 其他项都不能进行省略
O(n ^ 2 + nlogn + n) == O(n ^ 2)

递归复杂度的计算

递归有相应的代价, 递归的深度是多少, 它相应所占据的

时间复杂度:

  • 内部一次递归: 方法的时间代价 * 深度
  • 内部多次递归: 可以通过树结构来脑补来进行判断

空间复杂度: 方法的空间代价 * 深度