1、算法:算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。

那么一个怎样的算法才能称得上是好算法,也就是说有没有什么标准来评判一个算法的好坏?

在此之前,咱们先来做个试验:

  用两种方式来实现求裴波那契数列第n项的值,一种方式用递归方式,第二种方式用普通循环方式。

  在得到结果之前,你猜猜那种方式计算结果更快一些,还是一样快?

  测试代码如下(JavaScript):

  1. /**
  2. * 1、递归实现斐波那契数列:
  3. * 1,1,2,3,5... 第n项 = 第n-1项 + 第n-2项
  4. * */
  5. function recursionFbi(n){
  6. if (n < 3) return 1;
  7. if (n == 3) return 2;
  8. // console.log("递归n: ", n);
  9. return recursionFbi(n-1) + recursionFbi(n-2);
  10. }
  11.  
  12. /**
  13. * 2、循环实现裴波那契数列
  14. * 1,1,2,3,5... 第n项 = 第n-1项 + 第n-2项
  15. * */
  16. function circleFbi(n){
  17.  
  18. if (n < 3) return 1;
  19. var a = 1, b = 1, c = 0;
  20. for (var i = 0; i < n; i++){
  21. if (i > 1){
  22. c = a + b;
  23. a = b;
  24. b = c;
  25. }
  26. console.log("循环i: ", i, ", c: ", c);
  27. }
  28. return c;
  29. }

这里输入几个数字做测试,大致记录下结果作对比。

当然每次测试同一个数字的计算时间不一定都相同,跟当前测试的电脑硬件配置,和其他应用同开有一定关系。

当输入n=51的时候,测试结果截图如下:

还有输入其他一些n值的统计数据:

  上面通过两种方式求裴波那契数列,表现出来的时间损耗值相差惊人!为什么会有这么大的差别?这体现了一个好的算法能让程序的运行效率事半功倍,一个糟糕的算法对于程序来说简直就是灾难!刚才这两种算法方式的区别,等下再分析。

2、现在,我们来说说如何来粗略的估算一个算法的好坏。

  我们对于算法的设计要求是:正确性、可读性、健壮性、时间效率高、存储量低。

  因此对于一个算法,我们在运行前,可以从这五个角度来进行判断分析,下面主要从时间效率和存储量角度来细说下:

  • 时间复杂度(time complexity):估算程序指令的执行次数(执行时间)
  • 控件复杂度(space complexity):估算所需占用的存储空间

  

  大O表示法是一种粗略的分析模型,能帮助我们快速估算一个算法的执行效率,我们用它来描述算法的时间复杂度。

  常见的时间复杂度有这些:

  在使用大O推导法时,对于常数阶,我们用常数1代替;有多阶项则只保留最高阶项;最高阶项的常数去除。如图:

  

这里贴上几个示例用来练习时间复杂度的计算(JavaScript):

  1. //算法复杂度:O(n)
  2. function testCount1(n){
  3. //指令计数:多个if算作一个指令
  4. if (n > 10){
  5. console.log("n > 10")
  6. }
  7. else if(n > 5){
  8. console.log("n > 5")
  9. }
  10. else{
  11. console.log("n <= 5")
  12. }
  13.  
  14. //指令计数:1 + n + n + n = 3n + 1
  15. for (var i = 0; i < n; i++){
  16. console.log("...testCount1...")
  17. }
  18. }
  19.  
  20. //算法复杂度:O(logn)
  21. function testCount3(n){
  22. //指令计数:n/2 = log2(n)
  23. //n=2 -> 1; n=4->2; n = 8->3; n = 16->4; n = 32->6
  24. //1=log2(2); 2=log2(4); 3=log2(8); 4=log2(16); 6=log2(32)
  25. while((n = n / 2) > 0){
  26. console.log("***testCount3***");
  27. }
  28. }
  29.  
  30. //算法复杂度:O(nlogn)
  31. function testCount4(n){
  32. //指令计数:1 + 2*log2(n) + log2(n) * (1+3n) = 1 + 3log2(n) + 3n*log2(n)
  33. for (var i = 1; i < n; i = i * 2){
  34. //1 + 3n
  35. for (var j = 0; j < n; j++){
  36. console.log(">>>testCount4>>>")
  37. }
  38. }
  39. }
  40.  
  41. //算法复杂度:O(n^2)
  42. function testCount2(n){
  43. //指令计数:1 + 2n + n * (1+3n) = 1 + 3n + 3n^2 = 3n^2 + 3n + 1
  44. for (var i = 0; i < n; i++){
  45. for (var j = 0; j < n; j++){
  46. console.log("...testCount2...")
  47. }
  48. }
  49. }

常见的时间复杂度所耗时间的大小排列如下:

3、掌握了大O推导法,我们用大O表示法来论证本文最开始计算裴波那契数列的两种算法的区别:

 3.1 递归方式算法,先看下图:

  

  可以得出,这里的递归方式算法用大O表示法来表示,它属于指数阶,可以粗略表示为:O(n) = 2^n

  3.2 而第二种循环方式算法为线性阶的,用大O表示法为:O(n) = n

  3.3 我们对比一下指数阶和线性阶的函数曲线图就知道,n系数越大,这两种方式的最后的结果相差越大。

    所以当n越大时,递归方式算法的计算次数呈指数级上升,最后次数结果越大,时间损耗数也就越多。

测试Demo地址:https://github.com/xiaotanit/Tan_DataStruct

JS数据结构第一篇---算法之复杂度判断的更多相关文章

  1. 数据结构与算法 java描述 第一章 算法及其复杂度

    目录 数据结构与算法 java描述 笔记 第一章 算法及其复杂度 算法的定义 算法性能的分析与评价 问题规模.运行时间及时间复杂度 渐进复杂度 大 O 记号 大Ω记号 Θ记号 空间复杂度 算法复杂度及 ...

  2. JS原生第一篇 (帅哥)

    "流程控制语句":if.for. 1.1 if 选择语句,给程序添加了多种执行路线. 1 if(){ 2  语句1 3 }else if(){ 4  语句2 5 }else if( ...

  3. JS数据结构第二篇---链表

    一.什么是链表 链表是一种链式存储的线性表,是由一组节点组成的集合,每一个节点都存储了下一个节点的地址:指向另一个节点的引用叫链:和数组中的元素内存地址是连续的相比,链表中的所有元素的内存地址不一定是 ...

  4. js入门第一篇

    简介:JavaScript 运行在客户端(浏览器)是一种客户端语言,javascript的引擎被称为JavaScript引擎,为浏览器的一部分广泛用于客户端的脚本语言 应用场景:网页特效, 服务端开发 ...

  5. 初识js(第一篇)

    初识javascript js是前端中作交互控制的语言,有了它,我们的前端页面才能"活"起来.学好这么语言显得非常重要,但是存在一定难度,所以一定要认真学习,充满耐心. js书写规 ...

  6. js无限轮播算法中干掉if判断

    无限轮播在网页应用中经常见到,这其中算法各有千秋,在学习算法分析一书中发现自增取余方法可以干掉一些不必要的if判断,具体代码如下: var arr= [1,2,3,4,5,6,7,8]; var in ...

  7. 第一篇:python中的判断语句和循环

    python与C语言的代码格式区别: 需注意:1.python中语句结束没有分号 “;” 2.python中严格要求缩进,且在判断和循环等语句中把括号用冒号代替. 3.经常使用tab键进行缩进. 4. ...

  8. JS数据结构第三篇---双向链表和循环链表之约瑟夫问题

    一.双向链表 在上文<JS数据结构第二篇---链表>中描述的是单向链表.单向链表是指每个节点都存有指向下一个节点的地址,双向链表则是在单向链表的基础上,给每个节点增加一个指向上一个节点的地 ...

  9. Three.js 第一篇:绘制一个静态的3D球体

    第一篇就画一个球体吧 首先我们知道Three.js其实是一个3D的JS引擎,其中的强大之处就在于这个JS框架并不是依托于JQUERY来写的.那么,我们在写这一篇绘制3D球体的文章的时候,应该注意哪些地 ...

随机推荐

  1. .net 6.0 新特性

    1. 属性初始化 class Person { public string Name { get; set; } public string Sex { get; set; } = "男&q ...

  2. 一些质量极高的project-based tutorials

    <let's build a simple xxx> build your own lisp ★ Crafting Interpreters (学生版)Implementing Funct ...

  3. English--倒装句

    English|倒装句 这一块主要进行英语中倒装句与强调句的透析,希望大家可以掌握倒装句.因为倒装句,实在是太常见了,加油哦~~ 前言 目前所有的文章思想格式都是:知识+情感. 知识:对于所有的知识点 ...

  4. JDBC注册驱动程序3种方式

    以MySQL的驱动为例,介绍注册驱动程序的3种方式 1:Class.forName("com.mysql.cj.jdbc.Driver");// 加载数据库驱动 package c ...

  5. android studio学习---Lint工具

    对代码进行测试是一回事,但同样重要的是.我们还需要在编写代码的同时引入各种最佳实践.这不仅能够显著改进性能表现,也能增加应用程序的整体稳定性.另外,经过合理结构调整的项目在维护方面也更为轻松. And ...

  6. 安装gcc-c++报错解决办法

    问题 每次安装依赖包gcc-c++的时候,经常会遇到包如下错误   Error: Package: libstdc++-devel--.el7_4..x86_64 (ultra-centos-7.4- ...

  7. python基础-面向对象编程之多态

    面向对象编程之多态以及继承.抽象类和鸭子类型三种表现形式 多态 定义:同一种类型的事物,不同的形态 作用: 多态也称之为"多态性".用于在不知道对象具体类型的情况下,统一对象调用方 ...

  8. svn忽略target文件

    背景:最近项目转移到svn上 发现:项目从svn拉取下来到eclipse中,发现有大量的文件改动,一看都是一些.project之类的配置文件或者是target文件夹,或者下面的文件 这些东西肯定是不需 ...

  9. shell中if语句的使用

    转载于:https://www.cnblogs.com/aaronLinux/p/7074725.html bash中如何实现条件判断?条件测试类型:    整数测试    字符测试    文件测试 ...

  10. windows定期删除文件

    :: 定时清理客户端上传导入包文件 @echo off title 清理客户端上传导入包文件 :: 导入包文件目录 set log_dir="F:\http\uploadzip\web\ht ...