头图

【算法】一问一答,为什么要学算法,以及如何学习

ken1992code

常见面试提问

工作中很少用算法,业务居多,为什么还要学算法?

  • 为了面试,作为应对程序员市场内卷的筛选手段。(❌)
  • 《数据结构与算法图解》的作者杰伊·温格罗说,如果你只在大学作业和求职面试中用到算法,说明你还没有见识过算法的真正威力。(✔️)

确实,作为计算机的基础,数据结构与算法确实是软件世界的底层材料。但是由于今天的计算机产业过于发达,很多功能已经高度封装,普通码农只需要应对业务层的功能即可。用到排序的时候,一个 Array.prototype.sort() 就够了,浏览器甚至还能帮你决定用插入排序还是快排。
作为普通码农的我们很难见识到算法的威力。
但是!但是!不要忘记:

程序设计 = 数据结构 + 算法

在程序设计中,这两个要素分表代表了两个理念:

数据需要组织和存储

基础类型有哪些?对象在硬件中是如何存储的?如何理解和应用 Set 数据类型?
Promise 队列无法组织?数据过多渲染卡顿?做游戏无法处理大量对象?
学习过数据结构之后,上面的问题都能比较容易地去理解。

最少资源完成最多的事情

排序算法中,操作只有简单的比较和交换,但是其中涉及的理念,可以应用于所有算法。仔细想想,都是比较和交换,结果都是一样的,为什么加入二分思想后的排序,效率提升了指数倍。
千禧年时期,很多人以为在未来性能再也不是限制了。无限的带宽、高帧率渲染的屏幕、匹敌计算机的手机,我们只需要大步前进实现业务,性能会跟上来的。但是 2021 年的现实是,带宽耗费高昂资金、带宽依然令人不满、一个网页 50MB、电池限制了不能特效开满、几百个应用抢占着内存。性能依然无比重要。

当我们拥有这些背景知识之后,CS 世界的很多概念,就变得容易理解。火焰图就是堆栈、Promise 链是异步队列、Set & Map 的用法、是否应该用 API sort()... 作为麻瓜当然能在魔法世界活下去,但是不理解魔法的话,要成为巫师就处处是阻碍。

上面的并不是主管观点。曾经在日常的开发中,我用 1 行的 merge(),顶掉了老代码十几行的解构浅复制;用 3 行的链式调用,顶掉了一个小文件和十几行代码。如此少量的、基础的语法和上下文的应用,都能产生这么好的效果,可想而知在更加深入的领域,比如库设计和图形,DSA 的知识是多么的重要。

语言特性是数据结构的子集,算法是正确编排逻辑的基石。

面试题里,为什么常见的是数组的操作,比如搜索和排序?

  • 面试官也只是学到了数组操作那种程度。(❌)
  • 有序数组是算法的常客,因为其常见性,以及基础性。(✔️)

一是常见。数组确实是开发业务时的常客。如果是学术型的开发,才会经常碰到链表、树、图这些难处理的数据。
二是基础。如果不是深度的算法开发,确实没必要把这关卡的这么死(笔试题中不考设计模式和软件工程也是面试方式的缺陷)。在数组的排序中我们已经能够学到大 O 记法的定义、理念以及缺陷了,作为基础入门已经足够了。

怎么记住所有的排序法?

  • 背下来(❌)。
  • 根据它的诞生以及发展,通过推理得到(✔️)。

这确实是个令人头痛的问题:难学,难记,还会忘(为什么算法那么难-微软-刘未鹏)。
但是如果我们理清了它的理念和发展历程,就不难了:

  1. 排序算法都只有两种操作,比较和换位
  2. 冒泡法是最简单、最暴力的方案,只需要循环地两两比较和换位
  3. 插入法同上,也是两辆比较后换位,把下一个值插入到合适的位置
  4. 选择法是对冒泡的改进,去除了频繁的换位操作,每轮只跟最值交换一次
  5. 至此,简单排序已经没有了能优化的方法。要优化就必须要在设计理念上产生突破。
  6. DL.Shell 发现,排序是个加速的过程,越是有序的数组,排序越快。故采用先分组、再排序、最后合并的希尔排序,成功突破了算法复杂度 O(n^2) 的限制,达到 O(n^1.5)
  7. 先分组的思想,启发了科学家们,让排序进入了O(n*logn) 时代。后续但是的排序法,成为“改进排序法”,此前的都统称“简单排序法”
  8. 堆排序是用二叉堆,来实现先分组后选择最后合并的过程
  9. 归并排序是用二叉树,实现同上的过程
  10. 快排的思想同上,不过数组拆分、排序是交叉进行的,最后合并。
  11. 至此,快排是目前最快的排序法

(未完待续...)

阅读 175

技术冲关,Work in English

274 声望
6 粉丝
0 条评论
你知道吗?

技术冲关,Work in English

274 声望
6 粉丝
宣传栏