[数据结构]算法的复杂度

本文通过驾车行驶的物理模型介绍时间复杂度和大O标记法,阐述如何计算和分析算法的时间复杂度。文章详细解释了时间复杂度的概念,指出它描述的是问题规模与运行时间之间的关系,并提供了计算时间复杂度的步骤,包括简化表达式和选取变化最快的项。此外,文章还探讨了计算时间复杂度在优化算法中的重要性。
摘要由CSDN通过智能技术生成

00 写在前面

        本文旨在利用一个简单的物理模型类比介绍时间复杂度(Time Complexity)的概念 并向读者讲解 如何使用大O标记法(O Notation)对算法的时间复杂度进行简单估计, 并完成文末的相似概念推导与练习

注:

1. 阅读本文需要您有一定的 计算机语言基础 并 了解一些典型的数学函数模型

2. 本文的代码都由Java写成

3. 驾车行驶的物理模型将贯穿全文, 需要您有一些物理基础


01 目录

目录

00 写在前面

01 目录

02 概念

2.1 时间的推导

2.2 问题规模(the Size of Input)

2.3 时间复杂度(Time Complexity)

03 时间复杂度的计算

3.1 大O标记法(O Notation)

3.1.1 使用步骤

3.1.2 复杂情况下时间复杂度的计算

3.2 我们为什么要这样计算

04 反思

05 推导与练习


02 概念

2.1 时间的推导

        想象你即将开车前往某个地方度假, 你如何预估行程所耗的时间?

        我们马上就能联想到 物理公式 时间T = 路程S / 速度V

                这里的速度V可以理解为 汽车行驶每公里所需要的时间(km/h)

                            路程S可以理解为 总公里数

        那么该公式可以变式为: 时间T = 总公里数N * 行驶每公里的时间t

                

        让我们分析一下上述公式的三个变量:

                ①行驶每公里的时间t: 

                               受很多因素影响, 如: 汽车的性能, 路况等, 但综合起来可以看作一个常熟

                ② 时间T: 因变量, 随N的改变而改变

                ③ 总公里数N: 自变量

        那程序运行的时间呢?

        最简单的, 我们同样可以使用上面的公式作为推导 时间T = 语句条数N * 每条语句的运行时间t

        同样的, 我们也来分析一下上述公式的三个变量:

                ① 每条语句的运行时间t:

                                受众多因素影响, 如: 是否同时运行多个程序, CPU的处理速度等, 综合起来也能看作一个常数

                ②时间T: 因变量, 随N的改变而改变

                ③ 语句条数 / 语句执行次数N: 自变量

        

2.2 问题规模(the Size of Input)

程序运行时间T = 语句条数N * 每条语句的运行时间t

其中, 语句条数 / 语句执行次数N, 可能受输入数据的影响

1. N不受输入数据影响的情况

void func(int input){
    System.out.println(1);
}

        无论input为多少, 该函数中的语句始终只有一条, 执行时间是固定的

2. N受输入数据影响的情况

void func(int input){
    for(int i=0;i<input;i++){
        System.out.print(1);
    }
}

        我们发现, 此时当input值变化, 语句执行次数也进行变化, 于是, 我们将输入值的大小称作 问题规模(the Size of Input)

2.3 时间复杂度(Time Complexity)

        在驾车出游的例子中, 我们可以把问题规模类比成 目的地n

        我们发现: 当目的地n发生变化时, 总路程N发生变化, 行程所需时间T也会发生变化

        同样的, 在程序运行的过程中, 问题规模n发生变化, 语句的执行次数N发生变化, 运行时间T也会发生变化

        时间复杂度, 是一个用于描述 问题规模n 与 运行时间T 间关系的数学模型      


03 时间复杂度的计算

3.1 大O标记法(O Notation)

3.1.1 使用步骤

1. 写出语句条数表达式T (用n指代问题规模)

int func(int input){
    for(int i=0;i<input;i++){
        System.out.println(0);
        System.out.print(1);
    }
    return 0;
}

T = n + n + 1= 2n + 1;

2. 取"变化最快"的项

如何判断"变化最快的项"?

① 比较n趋近于正无穷时的变化趋势: 可以画函数图进行比较

②常见的比较 (从左到右随n的变化 由慢到快)

常数 < logn < n < nlogn < n^2 < n^3 < 2^n < n! < n^n

void func(int input){
    for(int i=0;i<input;i++){
        System.out.println(0);
        System.out.print(1);
    }
}

T = 2n + 1 -> 2n

3. 去掉该项的系数

int func(int input){
    for(int i=0;i<input;i++){
        System.out.println(0);
        System.out.print(1);
    }
    return 0;
}

T = 2n + 1 -> 2n -> n -> O(n)

上述实例代码的时间复杂度用大O标记法表示为O(n)

3.1.2 复杂情况下时间复杂度的计算

什么是复杂情况?

        出现函数, 多个循环时

如何解决?

        按块写出时间复杂度并相加, 选取最慢的时间复杂度

常用时间复杂度所耗费的时间从小到大:
O(1) < O(longn) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)

        注: 常数阶在该方法中统一用 1 表示

例:

int func(int input){
    int count = 0;

    for(int i=0;i<input;i++){
        count++;
    }
    
    for(int m=0;m<input;m++){
        for(int n=0;n<input;n++){
            System.out.print(1);
            count++;

        }
    }
    
    return 0;
}

1. T = 1 + n*1 + n*n*2 + 1 

2. 化简为大O标记法:

T = O(1) + n*O(1) + n*n*O(1) + O(1)

   = O(1) + O(n) + O(n^2) + O(1)

3. 根据上表选出变化最快的

T -> O(n^2)

上例代码的时间复杂度为 O(n^2)

3.2 我们为什么要这样计算

        如果你想驾车去一个很近的地方, 只需要实际去走一圈就可以得到确切时间, 但如果去一个非常遥远的地方, 尝试的成本是很高的

        程序也是一样, 这样的计算能够帮助我们对算法的效率有一个初步的估计,进而也能够成为我们优化算法的一条思路


04 反思

问问自己以下问题:

1. 本文主要介绍了哪些概念? 它们之间有什么联系?

2. 本文使用了什么例子介绍的这些概念? 如何用这个例子串起所有概念?3.


05 推导与练习

空间复杂度定义(摘自百度): 一个算法在运行过程中临时占用存储空间大小的量度

        请你使用本文的思路 尝试推导 空间复杂度的相关概念, 并推导下列代码的空间复杂度 (答案在文末哦, 请先尝试独立完成吧)

void bubbleSort(int[] array) {
 for (int end = array.length; end > 0; end--) {
   boolean sorted = true;
   for (int i = 1; i < end; i++) {
     if (array[i - 1] > array[i]) {
       Swap(array, i - 1, i);
       sorted = false;
     }
   }

   if (sorted == true) {
     break;
   }
 }
}
int[] fibonacci(int n) {
 long[] fibArray = new long[n + 1];
 fibArray[0] = 0;
 fibArray[1] = 1;
 for (int i = 2; i <= n ; i++) {
 	 fibArray[i] = fibArray[i - 1] + fibArray [i - 2];
 }
 return fibArray;
}
long factorial(int N) {
	return N < 2 ? N : factorial(N-1)*N;
}

继续向下拉是答案哦

答案

1. O(1) 

2. O(1)

3. O(N)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只米黄色长腿驴

感谢支持,祝你有美好的一天

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值