范文健康探索娱乐情感热点
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

一文讲透算法中的时间复杂度和空间复杂度计算方式

  前言
  作为一名"程序猿",大家应该都听过这么一句话:程序=数据结构+算法。
  这句话是由瑞士计算机科学家尼古拉斯·沃斯(Niklaus Wirth)在 1984 年获得图灵奖时说的一句话,这位大佬还以这句话为名出了一本书《Algorithms + Data Structures=Programs》,从此这句话就成为了大家耳熟能详的一句名言。
  随着时间的推移,不管这句话是不是非常准确,但至少能说明数据结构与算法对程序来说是非常核心的基础,如果我们想要写出更多优秀优雅的代码,那么数据结构与算法是必须要掌握好的。 为什么要学习算法
  很多人可能觉得,我不会算法,代码一样写得很"溜",算法这东西似乎用处不大。现在互联网的发达,我们想要什么几乎都可以在网上找到现成的,各种框架功能十分强大,似乎看起来确实不用算法也可以写出"好代码"。然而假如我们不懂算法,比如项目中用到了排序,我们如何评估代码的执行效率?再比如最常用的  ArrayList   和 LinkedList  ,我们该如何选择,又比如说我们需要去集合中找某一个数,又该如何写出性能优秀的代码呢?
  同样的代码,如何判断谁的代码是优秀的代码?可读性,可扩展性,健壮性可能都可以用来判定,然而这些东西我觉得并不能直接体现出你代码的优秀,因为对用户而言,访问你的代码响应速度快那就是优秀的代码,相反,动辄响应几秒甚至更长时间的接口,恐怕就算你可读性再好,再健壮也称不上是好代码。
  所以说一段代码是否优秀,最直接的判断标准就是性能,而如果要写出高性能的代码,那么就必须要了解算法,而且抛开这个因素,但凡不想一辈子都写  CRUD   代码的,也需要去了解算法,我们使用的很多框架和中间件底层都有数据结构和算法的身影,学好算法对我们源码阅读时理解其设计思想也是大有裨益的。
  要说功利性的目的,那就是面试,目前很多大厂的面试,算法基本必面,所以想进大厂的话,咱们也得好好学学算法。 算法难学吗
  提到算法,很多人的第一反应就是太难学了,学不会,或者说经常是看完就忘了,但是其实对于我们一个普通的开发者而言,因为并不需要我们去发明算法,我们需要的仅仅只是去灵活的运用算法,所以并不需要非常扎实的数据基础,当然基本的数学常识还是要有的。
  如果说需要去发明设计一款算法,那就要去推导去证明算法的可行性,这种是需要具有非常扎实的数学基础的,一般人确实无法做到,然而我们普通程序员口中提到算法无非是二分查找法,哈希算法等,高级一点的就还有回溯,贪心,动态规划等等,这些所谓的算法都是已经有现成的公式了,我们要做的无非就是理解它,然后灵活的运用它。这就和我们以前学习数学公式一样,给你一个公式,然后你去做题,做题的过程其实就是去灵活地运用这个公式。
  算法也是同理,都是有特定方法和特定思路的,我们也并不需要去推导证明这种方式为什么可行,所以学习算法没有其他诀窍,就是先理解思路,然后多练,等熟练了,自然就可以灵活运用了,也不会说学了立刻就忘了。学完就忘无非两个原因,一是没理解,二是没有练习巩固。 复杂度分析
  数据结构与算法经常是放在一起讲,这两者是没办法独立的,因为算法是为了达到某种目的的一种实现方式,而数据结构是一种载体,也就是说算法必须依赖数据结构这种载体,否则就是空谈。换句话说:数据结构是为算法服务的,而算法又需要作用在特定的数据结构之上。
  一个算法到底好不好,我们如何去评价?前面我们提到了,你的代码好不好,最直观的就是看响应速度,算法也一样,同样实现一个目的(比如说排序),谁的算法速度快,我们就可以认为谁的算法更优,如果说两种算法实现的速度差不多,那么我们还可以去评价算法所占用的空间,谁占用的空间少,那么就可以认为谁的算法更优,这就是算法的基础:时间复杂度和空间复杂度。
  学习算法之前,我们必须要学会如何分析时间复杂度和空间复杂度(也就是"快"和"省"),否则自己写出来的算法自己都不知道算法的效率。 时间复杂度大 O表示法
  接触过算法的都知道,算法的时间复杂度是用大写的"O"来表示的,比如: O(1)  ,O(n)  ,O(logn)  ,O(nlogn)  ,O(n²)   等等。
  时间复杂度的全称是渐进时间复杂度,表示算法的执行时间与数据规模之间的增长关系,上面的这种时间复杂度表示法并不能真正反应一个算法的执行时间,反应的只是一个趋势,所以我们在分析复杂度的时候要关注"变",忽略"不变"。
  变量指的是变量,也就是一段代码的执行时间是随着变量的变化而变化的,而不变指的是常量,也就是不论我的变量如何改变,执行时间都不会改变。
  接下来我们就实际的来分析下常用时间复杂度的例子来练习一下。 O(1) 常数阶
  0(1) 复杂度算法也称之为常数阶算法。这里的  1   是用来代指常量,也就是说这个算法的效率是固定的,无论你的数据量如何变化,效率都一样,这种复杂度也是最优的一种算法。public static void print(int n){     int a = 1;     int b = 2;     int c = 3;     int sum = a + b + c;     System.out.println(sum); }
  上面的示例中不论有多少行代码,时间复杂度都是属于常数阶段。换言之:只要代码不存在 循环 , 递归 等循环类调用,不论代码有多少行,其复杂度都是常数阶。 O(n) 线性阶
  O(n)   复杂度算法也称之为线性阶段。比如下面这个示例我们应该怎么分析复杂度呢?public static void print1(int n){     int a = 0;     for (int i=0;i2->4->8->16->32->64   一直到等于 n   为什么才会结束,所以我们得到了这样的一个公式:2^x=n  。
  也就是说我们只要计算出  x   的值,就得到了循环次数,而根据高中的数学知识我们可以得到 x=log2n  (2   在下面,是底数,试了几种方法都打不出来,放弃了),所以根据上面线性阶的分析方法,我们省略常量,就得到了示例中的算法复杂度为 O(log2n)  。
  同样的分析方式,下面的例子,我们可以很快地分析出复杂度就为  O(log3n)  :int i=1; while (i <= n) {     i = i * 3; }
  上面得到的  log3n   我们可以再做进一步的转换:log3n=log32 * log2n  ,而 log32  (注意这几个地方的情况 3   是底数,在下面) 是一个常量,常量可以省略,所以也就得到了:O(log3n)=O(log2n)  。同样的道理,不论底数是多少,其实最终都可以转化成和 O(log2n)   相等,正因为如此,为了方便,我们算法中通常就会省略底数,直接写作 O(logn)  。
  上面的数学公式大家如果忘了或者看不懂也没关系,只要记住不论对数的底数是多少,我们都算作  O(logn)  ,而对于一个算法的复杂度是否是对数阶,还有一个简易的判断方法:当循环中下标以指定倍数形式衰减,那么这就是一个对数阶。O(nlogn) 线性对数阶
  如果理解了上面的对数阶,那么这种线性对数阶就非常好理解了,只需要在对数阶的算法中再嵌一层循环就是线性对数阶: int i=1; for (int j=1;j<=n;j++){     while (i <= n) {         i = i * 2;     } }
  分析了前面这些最常用的时间复杂度,其实我们可以得到以下规律: 只要是常量级别,不论多大,效率都是一样的(如:常量级复杂度例子)。 分析一段代码的时间复杂度,只需要分析执行次数最多的一段代码(如:所以例子中我们只分析了循环体中代码执行次数)。 嵌套代码的复杂度等于嵌套内外代码复杂度的乘积(如:分析线性对数阶复杂度的例子)。 其他复杂度
  除了上面常用的复杂度之外,另外还有指数阶,阶层阶,根号阶等,这些接触的相对会较少,我们就不特意做分析了,如果大家感兴趣的话,可以自己去了解下。 组合式复杂度分析
  前面我们分析的都是只有一段代码比较复杂的情况下得到的复杂度结果,那么假如我一个算法中,有多段代码都比较复杂呢?这时候复杂度该如何分析? 取最大复杂度作为整个算法复杂度
  我们先看下面这个例子: public static void print1(int n){     for (int i=0;i<1000;i++){         System.out.println(i);     }     for (int j=0;j

这个方法就是在一个指定数组中找到指定元素的下标,找不到就返回 -1,这个方法比较简单,应该比较好理解。

注意这个方法中的循环体,如果找到元素,那么就直接返回,这就会有一个现象,那就是我这个循环体到底会循环多少次是不确定的,可能是 1 次,也可能是 n(假设数组的长度) 次,所以假如我们要找的元素就在数组中的第一个位置,那么我循环一次就找到了,这个算法的复杂度就是 O(1),这就是最好情况时间复杂度。

最坏时间复杂度

理解了最好时间复杂度,那么最坏时间复杂度也很好理解了,那就是数组中不存在我要找到元素,或者说最后一个值才是我要找的元素,那么这样我就必须循环完整个数组,那么时间复杂度就是 O(n),这也就是最坏时间复杂度。

平均时间复杂度

最好时间复杂度和最坏时间复杂度毕竟只有特殊情况才会发生,概率还是相对较小,所以我们很容易就想到我们也需要有一个平均时间复杂度。

我们简单的来分析一下,为了便于分析,我们假设一个元素在数组和不在数组中的概率都为 1/2,然后假如在数组在,那么又假设元素出现在每个位置的概率也是一样的,也就是每个位置出现元素的概率为: 1/n

所以最终得到的平均时间复杂度应该等于元素在数组中和元素不在数组中两种情况相加。

  • 元素在数组中的复杂度

因为元素在数组中的概率为 1/2,然后在每个位置出现的概率也为 1/n。假如元素出现在第一个位置,复杂度为 1*(1/2n);假如元素出现在第二个位置,复杂度为 2 * (1/2n),最终得到当前场景下时间复杂度为:1*(1/2n) + 2 * (1/2n) + ... + n*(1/2n)=(n+1)/4。

  • 元素不在数组中的复杂度

前面已经假定了元素不在数组中的概率为 1/2,所以当前场景下的时间复杂度为:n * (1/2),因为元素不在数组中,那么这个算法必然会将整个循环执行完毕,也就循环是 n 次。

最后我们把两种情况的复杂度之和相加就得到了平均时间复杂度:(n+1)/4 + n/2 = (3n+1)/4,最终我们将常数类的系数忽略掉,就得到了平均时间复杂度为 O(n)

均摊时间复杂度

均摊时间复杂度的算法需要使用摊还分析法,计算方式相对有点复杂,而且使用场景很有限,本文就不做过多介绍了。

空间复杂度

空间复杂度全称就是渐进空间复杂度,用来表示算法的存储空间与数据规模之间的增长关系。和时间复杂度一样,空间复杂度也是用大 O 进行表示。

其实学会了分析时间复杂度,那么空间复杂度的分析就简单了,主要就看我们在一个算法当中到底有没有使用到了额外的空间来进行存储数据,然后判断这个额外空间的大小会不会随着 n 的变化而变化,从而得到空间复杂度。

我们来看一个给数组赋值例子,假设这就是一个算法,我们可以来分析下这个算法的空间复杂度:

public static void init(int n){     int a = 0;     int arr[] = new int[n];     for (int i=0;i
华为手机右上角竟隐藏扫描仪,按下这个按钮,再也不用去打印店了大家好,我是分享科技小达人今天跟大家探讨的问题是华为手机隐藏的扫描仪用了这么多年的华为,我也是今天才发现,原来华为手机右上角竟隐藏扫描仪,按下这个按钮,再也不用去打印店了。首先我们5G手机红米k30和红米10X选哪个?数码新风暴,带你聊数码!5G手机红米K30和红米10X选择哪个好?在红米10X的发布会上,红米梳理了4和品牌系列,从高到底分别是K系列,X系列,note系列以及入门的数字N系列。可VIVOZ5手机怎么样?vivoZ5这款手机怎么样,今天就从我个人方面来简单评价一下这款手机。价格方面vivo官方商城Z5共五个不同的存储版本分别为(664GB)(6128GB)(6256GB)(梦幻西游比尔盖茨发布个人年度喜爱书单微软联合创始人比尔盖茨度过了动荡不安的一年。他跟前妻梅琳达弗伦奇盖茨的离婚案于8月最终完成。5月,当离婚的消息首次传出时,纽约时报和华尔街日报的报道称盖茨在结婚期间有可疑行为。而在用实际行动支持联想话不多说,用实际行动支持联想品牌!我就不明白,如今的pc市场,不买联想买什么?难道一定让联想关门大吉,让外来品牌占据我们的市场?自从2004年购买了一部联想翻盖手机,就一直是联想品AppStoreAwards2021榜单揭晓这是属于梦想信念与坚持的高光时刻如果说系统是设备的灵魂,那App便是注入这台设备的个性。从2008年至今,AppStore这家缔造个性的工厂已经走过十几个年头。那你有没有好奇过,铸造个性的工程师,究竟有多少人?截联想目前的困境,柳传志和杨元庆是否该退位让贤?国家应该改组联想,就像改组安邦保险一样。把违法犯罪人抓起来,把联想改名。早该退出了,还得严查杨柳之徒不是退让的问题,而是积极回答司马南和网民的问题,如果属实,立即严惩不贷追究贱卖国存储模组厂商3。0时代将至,定制化成为核心竞争力如果一家企业的成长只依赖行业,代表它的竞争力是不够的,不管行业发展是否一帆风顺,企业的成长率都必须要超过行业的平均水平,这是这家企业的绝对竞争力。在集邦咨询2022存储产业趋势峰会微商教父被罚破产?网友割韭菜的套路称为微商教父的龚文祥,估计真的要退出江湖了。12月2日,红星资本局注意到,在社交网络上,一张龚文祥致全体触电会老会员最后一封信的微信消息截图显示,龚文祥社群内部称,将解散社群触电会元宇宙来了,这波又是割韭菜?元宇宙的最终形态,按照各路大神的想象是把人插上各种管子,连上各种接口,一会儿一个神经元信号,一会儿一滴营养液。反正想想都觉得不靠谱,这么搞下去,活着还有什么意义吗?普通人还有什么价打败电商系列之六电商的进货其实,写这个题目的时候,感觉有点不太符合内容,因为,有些电商是自产自销,不需要进货的。但是,考虑到比较容易理解,还是这么写了,大家先凑合着看吧,毕竟内容才是关键。电子商务,包括但不
快充升级不加价!realme新机让小米再失一分在智能手机行业里,性价比一词在以前都能让大家想到小米,但在今年,谈及性价比的时候,大家又会多想起一个品牌,这就是realme。从今年发布的机型上来看,realme的多款机型都在对标耳机上面为什么要标LR(左右),如果我不按照它上面写的戴是不是音效会不同?人有两只耳朵,一只左耳,一只右耳,声音从不同的方向传入耳朵,经过大脑的计算就可以定位出声音发出的位置,这是在实际中的情况。为了模拟这样的情况,现在的音响产品和音响制品都会根据左右耳鸿蒙OS预计6月向消费者全面推送,为什么手机友商不支持?鸿蒙一出来,很多人都不相信鸿蒙系统是真的,许多友商会不搭载鸿蒙的,自己深耕的渠道改变友商们是很难改变的,并且都处于竞争关系,所以要看友商对系统的支持程度,主要还是看鸿蒙的发展。一个苹果iPhoneM1iPhone13新图曝光不对称摄像头亮了刚刚,外媒曝光了一组由大神AntoniodeRosa设计的苹果iPhoneM1(iPhone13)新概念渲染图。新机采用了全新不对称设计非常抢眼,祖传刘海也没了,还搭载了新CPU,iOS14。6正式版升级功耗增加了在经过两个iOS14。6RC版升级更新之后,苹果终于向iPhone手机用户推送了iOS14。6正式版升级更新。对于iOS14。6正式版升级更新来说一个重要的升级就是解决了iPhon华为P30Pro新版本现身工信部12512GB华为P30系列将于今晚亮相,该系列的信息在上个月就获得了入网许可证,其中型号为ELEAL00TL00和VOGAL00AL10,分别对应华为P30P30Pro。工信部并没有公布证件照果断收藏!一张版图带你摸清全球10大自动驾驶联盟布局中国汽车报随着自动驾驶汽车方兴未艾,众多车企和科技公司都在不断加码投资,但作为一种新兴技术自动驾驶不仅研发成本很高,而且在技术上具有不确定性和复杂性。为了分摊成本以及解决技术难题,几乎每家汽特斯拉曝华裔员工盗取密文件跳槽,小鹏汽车回应将内部调查本以为是风口,你真的站上去却成为了浪尖。小鹏汽车就是这样。特拉斯的一纸诉状,让这家中国新的自动驾驶进入者成为了争论焦点。愤怒的特拉斯要求其华裔员工曹光植及其新东家将被认为窃取的商业周黑鸭创始人从20平小作坊到百亿上市公司,就靠这4条原则第一经营企业,逐利则败历史上所有伟大的公司,虽然一定盈利,但它们都不是追求利益最大化而成功的,比如苹果Facebook谷歌。周黑鸭以这些企业为榜样,从不刻意追求利益最大化,从而成就如果黄章当时没有拒绝雷军建议,魅族的历史是否会改写?关注我,获取更多深度解读历史这东西,当年展望未来,还没有小米呢,谁知道魅族会发展成什么样,如今回头看,小米上市了,魅族疲惫了。不讲什么冥冥之中自有定数那套虚的,做企业的不讲玄学,讲关于手机降价快的那些事手机现在是人手一部,买手机也是一个重要的选购环节,对于手机的价格毋庸置疑越好越贵,但降价也快,比如三星,被戏说跳水冠军,手机利润越高,可降的价格越高,现在收入比较一般的人群基本都在