简介
本文主要从业务程序猿的角度来阐述问题。
2019.2.26 补充:为什么做搜索的公司技术都很牛?为什么要学数据结构与算法?为什么业务程序猿感觉数据结构与算法没用?剖析搜索引擎背后的经典数据结构和算法 光一个最最简单的搜索引擎涉及的数据结构和算法就有:图、散列表、Trie 树、布隆过滤器、单模式字符串匹配算法、AC 自动机、广度优先遍历、归并排序等。
首先,我们先回答一个孪生问题,再从“业务发展阶段” 及 “X/Y问题”视角来论证一下。
业务程序猿为什么要学习数据结构与算法
首先,笔者针对这个问题问了好几个大牛, 汇总如下
- 这不是大学基础专业课吗?基础的东西,也是it行业都必须要掌握的,不要问为什么要学,这是软技能,必须掌握
- 具体的数据结构是次要的,对目标问题的可利用的属性、数学模型的特殊属性、以及运行系统的物理属性保持高度敏感才是关键。数据结构课程不厌其烦讲解那么多例子就是让你建立这种“机敏”的世界观
- 数据结构基本就干两件事:对特定问题的有效存储,以方便更有效的检索。
- 不同的公司、不同的人做rpc框架,架构设计思路都差不多,最后实现的功能也差不多。但有的人做出来的框架 bug很多、性能一般、扩展性也不好,只是内部使用,而有的人可以被apache收录。高手之间的竞争其实就在细节,细节在技术上往往就是数据结构和算法。
- 数据结构不是最用不上的,数据结构是最普遍的,就像你可能认为数学是最用不上的时候,其实它无处不在
- 技术会有几个终极目标,比如最好的性能(包括最少时间和最少空间占用),还有最快交付结果。第一个和数据结构算法关系密切。虽然多数人并不需要自己写算法,只需要crud,但走到高级技术时,就要自己直面难题,不了解底下原理的话,就不容易做出合适的选择以及出深刻问题时如何排查。
- 数据结构,算法,作为编程基础,很有用,但未必有针对性的有用。很多日常工作可能根本不会直接用到。比如,高等数学有用吗?肯定有用,对你实际工作有很大帮助吗?未必,在实际逻辑开发中可能作用还不如一个简单的设计模式有用。我觉得你要看针对性,比如我是前一两年开始研究深度学习的时候,才去复习线性代数的一些算法比如梯度下降。如果关注架构,领域建模等层面,不太需要对数据结构和算法随时保持新鲜的记忆,有一点点“肌肉记忆”即可,如果你要做偏底层的开发,比如Southgate这种,才那可能会直接用到算法。
- 我觉得数据结构和算法属于提升层次的一个东西,具体点,对数据结构和算法敏感通常代码审美能力比较好,知道什么代码是好的,什么代码是低效的,数据结构最大的作用就是简化代码的复杂度和提高代码的维护性,典型的例子就是比如你用个前缀树啥的做搜索你可以很清楚时间复杂度和空间复杂度是多少,如果没这种数据结构的概念就容易写出低效的代码了。再补充一点,开源方案非常多,我们选择一些方案,进行技术选型的时候肯定会去稍微看看代码,美的代码会促进你使用,而评价美与丑就是看里面一些数据结构和小的算法的使用
笔者自己在交流中的一些体会
- 很多时候,是不学导致用不到,学到自然会找办法用到。就好比学英语,英语不好的程序猿不看英文文档,自然也体会不到英文的用处。
- 跟业务领域有关系,比如你在一家做地图的公司上班,对“图”相关的算法是一定要了解的。
业务发展阶段
有时候单说问题本身,是说不出所以然的,要place it in context,本文将context 定位为 公司的发展阶段。
一个互联网公司的发展通常有以下阶段:
- 业务为重,因为要生存
- 业务与技术并重,生存是第一的,但量级增大导致技术拖了后腿
-
技术驱动业务,最明显的体现在两个地方
- 大公司做一个app的成本极其低廉
- 最近流行的 为用户、主播、商家“赋能”
具体的说
- 互联网公司早期业务的本质是信息化,信息化体现在技术上就是crud,也就有了很多crud boy
- 早期用户、数据量不大
- “业务为重”体现在技术上 就是尽快的交付,无暇顾及数据结构与算法
- 后续,用户、数据量增大本身 对技术构成挑战
- 竞品的出现,以及用户需求的提高,不能止步于信息化,需要个性化、智能化
大部分公司 处在前两个阶段,所以业务程序猿 面对的事情更多是信息化和快速交付,因此对数据结构 与算法的 必要性感受不深。
一个很直观的例子, 大家谁能说的清楚自己的项目扛得住多大的QPS?有没有试过单机最大扛多少QPS?有没有体验过 最大QPS 下代码会出现哪些问题?很少。为何很多业务程序猿很少考虑这个问题呢?因为出了问题哪有时间想这些,代码逻辑没错就行,性能不够就加机器啊。
X/Y 问题
X/Y 问题说的是:你让我干Y,但其实为什么需要Y呢,是因为X,而实现X的方法 不是只有Y。说的是 做事情、看问题 要寻找本源。针对本文的问题可以衍射出两个问题
- 当我在说“数据结构与算法”的时候,我在说什么
- 数据结构与算法是Y,那么X是什么?
对数据结构的认识问题
大部分人在说 数据结构 和算法的时候,其实说的是大学学的《数据结构》那本书,再具体一点就是清华大学出版社的那本。那本书 定义了 我们看到 数据结构 这四个字时的条件反射,即线性表、树、图、排序算法等。
所以,我们说学习数据结构与算法有什么用?对大部分人来说,可以转换为:学习“线性表、树、图、排序算法” 有什么用? 就这个具体问题而言,除了代码里必不可少的数组/List 之外,其它的确实用的少。再者,笔者确实没碰到业务场景说 一定要将ArrayList 替换为LinkedList 。
对应前文中大牛提到的观点:数据结构基本就干两件事:对特定问题的有效存储,以方便更有效的检索。 所以数据结构不只是线性表、树和图,业务数据的结构化都可以归类到数据结构问题,进而考量数据有哪些检索场景?是否高效?
真的是为了数据结构本身么?
我们学习数据结构 与算法 是为了“更优的数据结构和算法” 本身么?不是,性能不高 加机器就好了呀。
我们学习数据结构与算法, 不是为了死记硬背几个知识点,是为了不断提高自己的意识
- 从无到有写代码的时候,培养对空间、时间浪费的罪恶感
- 从有到更好。出了问题,你的应对手段多一个思维方向,而不是只有“加机器”/“求助” 两条路
结合笔者的工作经历提一个问题:netty最牛的地方在哪里?用了nio?用了主从线程模型?内存零拷贝?数据处理pipeline?使用arena 接管内存分配和释放? 都对也都不对,是netty 在不断迭代的过程中,不断地对自己提要求,不断地挖掘问题点以支持更高的性能。
netty 的版本一直在迭代,业务当前很稳定,自然没有必要升netty的版本。类似的,如果你没有这样的意识,学数据结构与算法 也毫无必要。
如何学习数据结构与算法——有度的学习
数据结构 在技术中的 整体地位
做偏中间件开发的人,对算法和偏底层的比如网络的运用是比较多的,一般数据结构和算法能力都比较好,但他们对“工程”架构的东西关注不足。
因此凡事都可以一体两面的去看,技术能力可以分为
- 基础能力,包括但不限于语言、计算机组成原理、操作系统、数据结构与算法等
- 工程能力,如何应用基础能力,以及需求分析、项目设计、测试、维护和文档等
- 技术管理,人员项目协调、进度把控、技术氛围等
数据结构、计算机组成原理、操作系统等 经过文章、博客、课本的普及,成为一种“显学”。而“工程/架构”、”技术管理“等 因为模糊 提的少, 被归类为软技能。软技能在做他人/自我评估时,便容易被漏掉,一些工程能力/管理能力还不错的同学 也容易因为数据结构 不好而觉得不自信。
结合上文公司的发展阶段也可以看到,业务从无到有的过程 对工程能力和技术管理比较看重,业务从有到更好阶段 则更为看重基础能力。
有理有利有节
记忆有以下几种
- 有随时“新鲜”的记忆
- 不常用但是了解原理的“常识“记忆
- “肌肉”记忆,跟直觉一样
工作内容尽量要覆盖在新鲜记忆上。结合公司的发展阶段 以及自己的兴趣 爱好 和 定位 来把控自己的学习节奏,要不要学?学到什么程度? 很多时候,学不到位会误事,太超前了则容易受挫,进而打击积极性。此外,要随着项目、阶段的变化调整自己的策略,有些事要提前布局,有些事被动跟进就可以了。
刷题
对于初学者来说,做题有点像是撞大运,非常依赖苦思冥想之后的灵光一闪。而高手做题则不然,他们的思路非常有章法,知道如何从蛛丝马迹的细节中锁定解法。所以这就是为什么有些题目用到的算法即使新手学过,但拿到题还是一样做不出来,而高手却能秒切的原因。当然想要拥有这样的功力也不是一朝一夕的,也需要长久、反复的训练。至少我们在刷题的过程中可以意识到这点,在做完题之后多尝试,尝试构建出从问题分析出解法的推衍过程。推衍得多了,自然熟悉的套路也多,做题也就会变得顺手起来。在面试的时候,这个技能同样非常有用。哪怕最后想不出解法,只要能合理地分析问题,找对思路,也是一个巨大的加分点。很多时候做到这样就足够打动面试官了。
计算机领域有一句名言:程序等于算法加数据结构。数据结构针对的是数据层面,提供数据的存储和查询,而算法针对的是操作层面,对数据进行操作,达成我们期望的效果。算法和数据结构相辅相成,算法基于数据结构实现,而数据结构的实现本身就需要用到算法。一道题本质上就是若干个算法和数据结构的组合,我们只要能找到合理的算法和数据结构,就可以获得AC。如果你觉得拿到题目之后很蒙圈,无从下手,那么不妨将算法和数据结构分开进行思考。
- 数据结构说白了就是数据的增删改查,只不过题目一般都会对性能做出要求,需要保证增删改查的复杂度满足一定的限制。但限制本身也是一种提示,因为常用的数据结构也就那么几种,熟悉了之后,一结合复杂度要求,几乎可以瞬间锁定。
- 算法就是在数据结构基础上对数据的进一步加工,使得满足题目的要求。比如搜索、动态规划、贪心等本质上都是数据的操作。
我们常说的LeetCode题,大体上可以分为三种:算法题、数据结构题和综合题。顾名思义,算法题就是以算法考察为主,比如排序、搜索、贪心、动态规划相关的问题,数据结构都比较简单,可能就是普通数组就行。数据结构题也类似,就是考数据结构,比如线段树、树状数组、链表、图等等,你不会这些数据结构就做不出来。最后一种就是综合题,既考察算法又考察数据结构。一般来说综合题最难,因为需要都会。总的来说,LeetCode Medium难度的题目,算法和数据结构只会主要考察一种。用到了比较高级的数据结构,就不会过多涉及算法,同样,如果需要对算法设计做深入思考,用到的数据结构就不会很难。而Hard难度的题,往往是这两者的结合,或者是某一方面的深入考察。
理解了这些之后,当你拿到问题感觉无从下手的时候,不妨可以将算法和数据结构拆开来思考。这道题对于数据增删改查有没有特殊的性能要求?可能需要用到什么数据结构?在有了对应的数据结构之后又该使用什么算法得到答案?说不定就能灵光一闪,找到突破口。此外,凭空思考一个最优解是很难的,相比之下先想出一个方法再慢慢优化要容易得多。所以不要看不起那些一眼就不是正解的“弱智”解法,它们经过优化是有可能构成正解的,很多时候这是我们效率最高的思考方式。这个方法在面试的时候尤其有用,面试官很多时候不是只想要一个正解。有时候你直接告诉他解法,他反而可能觉得你是背的答案或者是刚好之前做到过。他更想听我们的思考过程,看看我们的思维能力以及分析能力。这种抽丝剥茧,一点点优化的方式是很多面试官喜欢的,即使离正解还差一点,也一样能得到高分。
个人微信订阅号