算法是用于解决特定问题的一系列的执行步骤。使用不同算法,解决同一个问题,效率可能相差非常大。为了对算法的好坏进行评价,我们引入 “算法复杂度” 的概念。

1、引例:斐波那契数列(Fibonacci sequence)

已知斐波那契数列:,求它的通项公式







求解斐波那契数列的方法有很多种,这里只介绍两种:递归法和平推法。

package com.atangbiji;public class Main {public static void main(String[] args) {// 输出通项F(n)System.out.println(fib1(1));System.out.println(fib1(2));System.out.println(fib1(3));System.out.println(fib1(4));System.out.println(fib1(5));System.out.println(fib2(70));}/** 求斐波那契数列(Fibonacci sequence)* F(1)=1,F(2)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*)的通项F(n).*//**  方法一:递归法*  最高支持 n = 92 ,否则超出 Long.MAX_VALUE* @param n * @return f(n) * */public static long fib1(int n) {if (n < 1 || n > 92)return 0;if (n < 3)return 1;return fib1(n - 1) + fib1(n - 2);}/**  方法二:平推法*  最高支持 n = 92 ,否则超出 Long.MAX_VALUE* @param n * @return f(n) * */public static long fib2(int n) {if (n < 1 || n > 92)return 0;//n:    1 2 3 4 5 ……//F(n): 1 1 2 3 5 ……long first = 1;long second = 1;for (int i = 3; i <= n; i++) {long sum = first + second;first = second;second = sum;}return second;}}

通过测试,我们可以发现:当n的取值较大时(如:n = 60),若采用递推法计算则会发现迟迟不出结果,若采用平推法计算则可以秒出结果。由此可见, 平推法的效率明显高于递推法。

2、如何评估算法的好坏?

  • 正确性

  • 可读性

  • 健壮性:对不合理输入的反应能力和处理能力。

  • 时间复杂度(time complexity): 估算程序指令的执行次数(执行时间)。

  • 空间复杂度(space complexity): 估算所需占用的存储空间。

注:一般情况下,我们主要考虑算法的时间复杂度。 (因为目前计算机的内存一般都比较大)

3、时间复杂度的估算

我们可以用程序指令的执行次数来估算时间复杂度。例如:

(1)函数test1

public static void test1(int n) {//总执行次数 = 14// 1(判断语句可以忽略)if (n > 10) {System.out.println("n > 10");} else if (n > 5) {System.out.println("n > 5");} else {System.out.println("n <= 5");}// 1 + 4 + 4 + 4for (int i = 0; i < 4; i++) {System.out.println("test");}
}

(2)函数test2

public static void test2(int n) {//总执行次数 = 1 + 3n//1 + n + n + nfor (int i = 0; i < n; i++) {System.out.println("test");}
}

(3)函数test3

public static void test3(int n) {//总执行次数 = 48n + 1// 1 + 2n + n * (1 + 45)for (int i = 0; i < n; i++) {for (int j = 0; j < 15; j++) { // 1 + 15 + 15 + 15System.out.println("test");}}
}

(4)函数test4

public static void test4(int n) {//总执行次数 = 3n^2 +3n +1// 1 + 2n + n * (1 + 3n)for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) { // 1 + n + n + nSystem.out.println("test");}}
}

(5)★ 函数test5

public static void test5(int n) {//总执行次数 = log2(n)/** n = 2 , 执行 1 次* n = 4 , 执行 2 次* n = 8 , 执行 3 次 * */while ((n = n/2) > 0) { // 倍速减小System.out.println("test"); // 只考虑这一句的执行次数}
}

(6)函数test6

public static void test6(int n) {//总执行次数 = log5(n)while ((n = n/5) > 0) {System.out.println("test"); // 只考虑这一句的执行次数}
}

(7)函数test7

public static void test7(int n) {//总执行次数 = 3n*log2(n) + 3log2(n) + 1// 1 + 2 * log2(n) + log2(n) * (1 + 3n)/** n = 2 , 执行 1 次* n = 4 , 执行 2 次* n = 8 , 执行 3 次 * */for (int i = 1; i < n; i += i) { // i = i + i = i * 2(倍速增大)for (int j = 0; j < n; j++) { // 1 + n + n + nSystem.out.println("test");}}
}

4、大O表示法

为了进一步简化复杂度的计算,我们一般使用大O表示法来描述时间(或空间)复杂度。它表示的是 数据规模为n 时算法所对应的复杂度。

大O表示法的性质:

(1)可以忽略常数、常系数和低阶项。








  • &#xff08;



    &#xff09;












  • &#xff08;



    &#xff09;


















  • &#xff08;






    &#xff09;


(2)对数阶一般省略底数,统称


























注:大O表示法仅仅只是一种粗略的分析模型,是一种估算。 它能帮我们快速了解一个算法的执行效率。

5、常见的复杂度

其中:

  • 当数据规模较小时, 各复杂度对应的曲线如下图所示。

  • 当数据规模较大时, 各复杂度对应的曲线如下图所示。

所以,当数据规模比较大时,复杂度为










我们就很难接受了。

6、斐波那契数算法复杂度分析

(1)递归法

public static long fib1(int n) {if (n < 1 || n > 92)return 0;if (n < 3)return 1;return fib1(n - 1) + fib1(n - 2);
}

假设计算




































的值已经得到,我们可以发现该函数每次执行的时间主要取决于求和运算。因此,该算法函数指令的执行次数等价于该函数被递归调用次数。








时,该函数的调用过程如下图所示。

所以,该函数被递归调用的次数




二叉树的节点数。

即:

因此,该算法的复杂度为










注: 细心的同学可能会发现,当






时,函数被递归调用的次数并不完全等于











这里需要说明的是:复杂度是一种估算,我们关心的不是具体的数值,而是量级和趋势。 所以,










呈指数级增长的趋势是毋庸置疑的。

(2)平推法

public static long fib2(int n) {if (n < 1 || n > 92)return 0;//n:    1 2 3 4 5 ……//F(n): 1 1 2 3 5 ……long first = 1;long second = 1;for (int i = 3; i <= n; i++) {long sum = first + second;first = second;second = sum;}return second;
}

显然,平推法的时间复杂度为







7、算法的优化方向

(1)用尽量少的执行步骤(运行时间)。

(2)用尽量少的存储空间。

(3)根据情况,空间换时间或者时间换空间。

更多关于复杂度的知识,我们会在后续数据结构和算法的设计与实现过程中穿插讲解。

(本讲完,系列博文持续更新中…… )


参考文献:

  • 《恋上数据结构与算法》,小码哥MJ

  • 《数据结构与算法》,邓俊辉

更多Java和算法教程,关注下面公众号:

“算法复杂度”其实并没有那么复杂相关推荐

  1. 20162311 算法复杂度-3

    算法复杂度-3 题目要求 实现情况 求一个整数二维数组Arr[N][N]的所有元素之和 我自己写了一个getSum的方法 算法的时间复杂度为O(n^2) 对于输入的任意 3 个整数, 将它们按从小到大 ...

  2. PHP复杂度,php 算法复杂度 时间复杂度 空间复杂度

    算法复杂度分为时间复杂度和空间复杂度. 其作用: 时间复杂度是指执行算法所需要的计算工作量: 而空间复杂度是指执行这个算法所需要的内存空间. (算法的复杂性体现在运行该算法时的计算机所需资源的多少上, ...

  3. .NET平台BigO算法复杂度备忘

    之前一篇文章提到BIG O算法复杂度的备忘录, 今天这个是.NET 平台下集合类相关的Big O 算法复杂度 今天先到这儿,希望对您有参考作用, 您可能感兴趣的文章: 数据结构与算法 Big O 备忘 ...

  4. O(n)级选排名第k位数(附上算法复杂度分析)

    算法简述 如果想要拿到第k位,一般说复杂度都比较高.例如,用快排等方式,要用了O(nlogn)水平的时间复杂度.就算是用快排改进,每次在快排的基础上,只排剩下的一部分,在平均水平上,也会变成了O(nl ...

  5. “算法复杂度”——其实并没有那么复杂

    算法是用于解决特定问题的一系列的执行步骤.使用不同算法,解决同一个问题,效率可能相差非常大.为了对算法的好坏进行评价,我们引入 "算法复杂度" 的概念. 1.引例:斐波那契数列(F ...

  6. 二分检索用途及复杂性_二分查找和三分查找哪个快?算法复杂度与常数无关?复杂度分析的常见误区...

    还记得两三年前,我初看一本算法书,看到二分查找算法的复杂度时,我发现了了不得的东西:二分查找每次查询范围减少一半,需要查询的次数是 ,它的复杂度是 . 我把它改成三分查找,每次查询两个数字与我的目标数 ...

  7. 算法复杂度分析(下)

    前一篇文章算法复杂度分析(上)讲述了复杂度的大 O 表示法和几个分析原则,这篇文章我们来讲讲另外几种复杂度,最好情况时间复杂度(best case time complexity).最坏情况时间复杂度 ...

  8. 排序代码(python,c++) 及 基本算法复杂度

    0.导语 本节为手撕代码系列之第一弹,主要来手撕排序算法,主要包括以下几大排序算法: 直接插入排序 冒泡排序 选择排序 快速排序 希尔排序 堆排序 归并排序 1.直接插入排序 [算法思想] 每一步将一 ...

  9. 老王带你理解算法复杂度O(1),O(N),O(N^2)

    上图对应的是算法复杂度的图片,X轴对应的是n(问题规模),Y轴对应的是执行的运行时间. 我们先从简单的复杂度解读O(1) 从上面的图片我们可以看到O(1)的复杂度是恒定的,一点波澜都没有,什么是O(1 ...

  10. 八大排序:Java实现八大排序及算法复杂度分析

    目录 QUESTION:八大排序:Java实现八大排序及算法复杂度分析 ANSWER: 一:冒泡排序 1.算法分析 2.时间复杂度分析 3.代码 二:选择排序 1.算法分析 2.时间复杂度分析 3.代 ...

最新文章

  1. Android手机系统adb常用的命令
  2. cuda安装和caffe
  3. gulp复制整个文件夹或文件到指定目录(包括拷贝单个文件)
  4. Python爬虫 - 解决动态网页信息抓取问题
  5. 2020 年微服务项目活跃度报告
  6. mysql bin.000013_"mysql-bin.0000*"占用空间问题及删除
  7. Python程序开发——第二章 条件语句和循环语句
  8. windows xp下Apache2.2.11整合Tomcat6.0.20
  9. POJ1742Coins
  10. qq象棋辅助 android,QQ象棋自动下棋
  11. 分布式系统的阿喀琉斯之踵:数据一致性!
  12. java微信开发之--更换背景图片
  13. matlab怎么做多元非线性拟合,如何用matlab进行多元非线性拟合
  14. Spring 事务传播行为
  15. 牛客网 - [牛客假日团队赛6]对牛排序
  16. 诺基亚智能手机内存不足等问题的解决
  17. u深度制作linux启动盘制作工具,U深度U盘启动盘制作工具怎么操作?U深度U盘启动盘制作工具使用...
  18. Fluent中的各种初始化
  19. carla学习笔记(十)
  20. 武汉光庭导航面试经历

热门文章

  1. 【云原生】Kubernetes(k8s)部署 MySQL+Dubbo+Nacos服务
  2. 一、重写muduo网络库之服务器编程及测试
  3. java计算机毕业设计精准扶贫管理系统源程序+mysql+系统+lw文档+远程调试
  4. 浅学Matlab:确定比赛的胜负问题
  5. JAVA园林公司OA系统计算机毕业设计Mybatis+系统+数据库+调试部署
  6. 《绝地求生:大逃亡》赚4亿美元,中国玩家比例最高
  7. 基于spring 的开源框架
  8. tensorflow/serving部署keras的h5模型服务
  9. 2016最新H5面试题(及答案)
  10. 虽然只是个“数字助手”,却是AI的一次飞跃