如何判断程序的复杂程度:时间和空间复杂度

本文介绍程序的时间复杂度和空间复杂度概念,详细分析了不同类型的复杂度及其在常见算法中的应用,包括数组、链表及跳表的时间复杂度对比。

如何判断程序的复杂程度:时间和空间复杂度

1. 时间复杂度:

使用大O表示法来表示程序的时间复杂度

常见的7种时间复杂度(复杂度由低到高排序)

  1. O(1):常数时间复杂度

  2. O(log(n): 对数时间复杂度

  3. O(n): 线性时间复杂度

  4. O(n^2):平方时间复杂度

  5. O(n^3):立方时间复杂度

  6. O(k^n):指数时间复杂度,k表示常数

  7. O(n!):阶乘时间复杂度

ps:

  1. 这里我们并不考虑前边的系数;O(1) 并不表示复杂度为1,也可以 是2、3等常数;O(n)表示程序运行了n次或者2n、3n次;以此类推其他时间复杂度

  2. 时间复杂度的判断,以一段代码的最高复杂度为准;

如何判断一段代码的时间复杂度

简而言之就是看内部某段代码的执行次数

  1. O(1):常数复杂度

    • int n = 1;
      System.out.println(n);
      
    • int n = 1;
      System.out.println(n);
      System.out.println(n+1)
      System.out.println(n+2)
      
  2. O(n):线性时间复杂度

    • for (int j = 0; j < n; j++) {
          System.out.println(j);
      }
      
    • for (int i = 0; i < n; i++) {
          System.out.println(i);
      }
      for (int j = 0; j < n; j++) {
          System.out.println(j);
      }
      
  3. O(n^2):平方时间复杂度

    • for (int i = 0; i < n; i++) {
          for (int j = 0; j < n; j++) {
              System.out.println(i + j);
          }
      }
      
  4. O(n^3):立方时间复杂度

    • for (int i = 0; i < n; i++) {
          for (int j = 0; j < n; j++) {
              for (int k = 0; k < n; k++) {
                  System.out.println(i + j);
              }
          }
      }
      
  5. O(log(n)): 对数时间复杂度

    这里演示的是以2为底n的对数

    • for (int i = 0; i < n; i = i * 2) {
          System.out.println(i);
      }
      
  6. O(2^n):指数时间复杂度

    • /**
       * 递归求斐波那契数列的第n项;可以通过画运行树的方式获得时间复杂度
       */
      int fib(int n) {
          if (n < 2) return n;
          return fib(n - 1) + fib(n - 2);
      }
      
  7. O(n!):阶乘时间复杂度

    • todo

小练习1:求和计算1~n的和

  1. O(n)

    int y = 2;
    for (int i = 0; i < n; i++) {
        y+=i;
    }
    
  2. O(1)

    使用了求和公式:sum = n(n+1)/2

    int y = 2;
    for (int i = 0; i < n; i++) {
        y+=i;
    }
    

小练习2:求斐波那契数列

  1. O(2^n):

    int fib(int n) {
       if (n < 2) return n;
       return fib(n - 1) + fib(n - 2);
    }
    
  2. O(n):该方法比递归要快得多

    int fib2(int n) {
        if (n == 1 || n == 2) {
            return 1;
        }
        int a = 1, b = 1, result = 0;
        for (int i = 3; i <= n; i++) {
            result = a + b;
            a = b;
            b = result;
        }
        return result;
    }
    

主定理

主定理(英语:master theorem)提供了用渐近符号(大O符号)表示许多由分治法得到的递推关系式的方法

常用算法中的应用
算法递回关系式运算时间
二分搜寻算法在这里插入图片描述在这里插入图片描述
二叉树遍历在这里插入图片描述在这里插入图片描述
最佳排序矩阵搜索(已排好序的二维矩阵)在这里插入图片描述在这里插入图片描述
合并排序在这里插入图片描述在这里插入图片描述

所有排序的最优算法都是O(nlog(n))

2. 空间复杂度

如何判断一段代码的空间复杂度

主要通过两部分进行判断:

  1. 数组的长度

    如果代码中应用了数组,那么数组的长度,基本上就是空间复杂度;
    e:一维数组的空间复杂度是O(n);二维数组的空间复杂度是O(n^2)

  2. 递归的深度

    如果代码中有递归,那么递归的深度,就是代码的空间复杂度的最大值

ps:如果代码中既有数组,又有递归,那么两者的最大值就是代码的空间复杂度

leecode有个爬楼梯的复杂度分析情况;可以进行练习

3. 数组和链表的时间复杂度分析

数组

随机增加:O(n)
随机查询:O(1)
随机删除:O(n)

链表

随机增加:O(1)
随机查询:O(n)
随机删除:O(1)

跳表

跳跃表(skiplist)是一种随机化的数据, 由 William Pugh 在论文《Skip lists: a probabilistic alternative to balanced trees》中提出, 跳跃表以有序的方式在层次化的链表中保存元素, 效率和平衡树媲美 —— 查找、删除、添加等操作都可以在对数期望时间下完成, 并且比起平衡树来说, 跳跃表的实现要简单直观得多。

简单来说,跳跃表是有序链表的一种扩展,在有序列表的基础上进行了升维处理
在这里插入图片描述
在这里插入图片描述
以上图片来自公众号:程序员小灰

随机增加:O(log(n))
随机查询:O(log(n))
随机删除:O(log(n))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值