算法与数据结构:初学者的全面指南

发表时间: 2024-01-09 17:32



注:不想听理论的可直接拉到底部看省流版,毕竟诸君中有好多位一贯是这么学习的,记结论套公式的见得太多了,对于某些人来说好像课本上除了公式和课后题之外,其它的都是废话,没办法,一个人有一个人的想法,不可强求。迷信权威不是好事,反智(无脑反权威)也未必是好事,老师嘛,能做的真的挺有限的,无非就是引导着入个门,指个大方向(让学生不要误入歧途,把时间浪费在花架子上面),再就是学生遇到新题目了,爷俩一块给讨论讨论,也就这点用。关键还是看学生个人,不想学,不肯往深学,追求短平快,那也没办法。

费流版

前两天@浮河先生让我帮他推荐几本数据结构书,还最好是c语言的,我觉得这没啥好推荐的,网上一搜一大堆,我再给一个必要性不是很大,所以就有了这篇文章,谈谈算法和数据结构的学习问题,我觉得这很重要。这门课程对于计算机学科来说,可以说是非常重要,但是教材嘛,真的就一言而尽,@浮河先生找我推荐书,正是因为我在另一个问题“为什么我会感觉中国大学教材很烂”下面吐槽了谭浩强先生和严蔚敏女士那两本书的事,毕竟大家都知道的。


教材嘛,多少年了,倒是更新一下呀,不要跟某些老师的祖传PPT一样,2023年还用着2013年写的PPT,十届学生学的一模一样的东西,那就不好了,是吧,足以说明此人教学上课时如何敷衍糊弄,毕竟人家《java核心技术》都更新到12版了,咱就不说学习一下人家Cay S.Horstmann教授的勤快,隔两、三年更新一版,至少稍微改点东西总可以吧,改PPT又不是写书,虽然咱很讨厌PPT这个东西,简单问题复杂化,几句话,再画个图就能说清楚的事,非要浪费时间做这么个玩意。


教材的事就不说了,下面开始讲如何学习算法和数据结构。其实没啥好讲的,无非就找两本好书看看,然后自个在机器上敲敲,熟悉熟悉,技巧性的东西,多写写,跑跑代码,就差不多可以掌握了,没什么好说的。


最好呢,就是先找一个讲课水平高的老师,跟着上课,先听,把核心的东西先掌握,那就是算法思想,这个是最重要的,贯穿计算机科学的始终,这个不好好学,就会有问题。正好最近跟别人讨论过这个问题,就顺带说说我的看法。因为我发现一般培训班出来的人就对这个比较排斥,觉得非常非常难,这就是算法思想没掌握,底子没打好,培训班的课程毕竟是市场产物,肯定就比较短视,只教市场上最火热的框架、技术之类的东西,比如ssm框架,vue框架,gin框架之类的,看似学了一大堆技术,但说实话,都是花架子,这种东西学再多不过也就是api caller,立不起来,5年经验跟1年经验没啥区别。


当一个人不了解一个东西的时候,就往往出现认知偏差,可能会把某个东西神化,比如说算法,他就会觉得这东西太高级了。这我就很疑惑:大学计算机系是个人都会的东西,哪里高级了?看不出来。一个工具而已,谁会觉得自己家里的铁锨和锄头高级?都是前人玩剩下的东西,非要给赋予一层神秘感,就很奇怪,总要把一个简单问题复杂化,这是很危险的,如果一个人在内心里将完成一件事的难度无限拔高,那么他很可能就无法完成那件事,毕竟未战先怯,兵家大忌,你都没有勇气去面对对手,那怎么可能战胜对手?(对,就把算法想象成一个对手)


当然,培训班的朋友,他要是能听劝,他就不需要上培训班了,他自个找教程,找基本经典的书就能学了,所谓老师,无非就是给个引导,学习的主体还是学生,他不愿意学你也没办法,总不能逼他吧,这种强迫人的事还是少做点好。小的时候逼迫孩子要好好学习,有的小孩聪明,长大了能理解父母的用意,但毕竟是少数,剩下的估计就闹矛盾了,然后家庭关系不睦,说到底还是把孩子逼得太紧了。有些家庭甚至极端到,算了,就不说了,咱这篇文章毕竟是讨论算法学习,聊一些社会新闻啥的总不太好。


那位网上认识的朋友,他觉得“算法这东西可不是谁都能搞的”。


我是这样回答他的:你非要这么说,那就没得说了,很简单东西,没必要复杂化,算法就是解决问题的能力,你以为是啥,为什么程序=算法+数据结构?因为你是要解决具体的实际问题,不是说学什么屠龙术,这些问题很可能就是你经常遇到的,别人一看就知道咋回事,迅速解了,你还要cv search一波,这不是聪明,投机取巧从来都不是聪明,你cv了代码,看不懂代码是在干啥,说白了就是搬运工,没有技术含量的事,随便找个人都能替代掉,不敢提涨工资,因为你可能学了好多年这个啥都不会,啥都没学到,最后35岁光荣毕业,外卖骑手+1,所谓高级程序员低级程序员无非就是解决问题能力的高低,跟工作年限真没太大关系,不然为啥人家愿意招985211应届生,也不愿意招培训班出来的,要想,要多想,就说到这吧,一会又被群体而攻之就不好了,毕竟忠言逆耳。


咱文明人,以理服人,用逻辑,用事实跟别人讨论,让他明白只会那堆花架子有什么危害。然后他让步了,说“你说的很对,掌握必要算法没啥毛病,我说的是指深入”,其实这句话跟没说一样,前面我都说了,算法最重要的就是他解决问题的思想了,掌握了就是深入了,没掌握就是不会,做再多题都白给,其实有些人与其把大量的时间浪费在“题海战术”上面,不如停下来好好想想,多思考思考,做题不是目的,做题就是为了掌握和巩固所学的知识,也就是算法思想。把做题作为目的,那就是本末倒置,但就是这么一个并不复杂的东西,好多人转不过弯来。

为什么我会说“群体而攻之”,“忠言逆耳”这样的话,因为之前真的遇到过,就在同一个群,这个群吧,大概培训班的学生多一点,就是说基本都是学了一堆花架子,然后科班的那一套计算机科学的东西,如计算机组成原理,操作系统,编译原理,计算机网络,算法设计,数据结构,数据库系统原理之类的东西,他是一个都没学过,这就导致他底子很差,只能干quick start, readme.md, cv search 之类的活,干啥都是面向百度编程,面向CSDN编程,稍微玩点花活就把他难住了,比如说限流,这个不就是流控吗?你都不用看算法,学过计算机网络的,学过TCP协议的,能不知道滑动窗口?毕竟这么重要的东西呢。我直接把leetcode上的滑动窗口的题目扔给他,人家一脸懵逼。


时间再往前,也就几个月前,我就说尝试着自己设计并编码系统这个事,也不是啥难的,本科论文水平,这种基本都是学术垃圾水平的东西,这有啥难度,结果就戳到人家痛处了,只编码,从不设计,都是听命干活的主,聊天就聊天,理性讨论,以理服人,毕竟学理工科的,只要你说的符合逻辑、符合事实,能立得住,能站得住脚,都服,没人一天天闲的整天找人抬杠的,这就是基本的科学素养,就是科学思维。然后那小孩吧,比较年轻,培训班出来的,他意识不到培训班他们的上限可能都达不到人家一些科班学生的下限,就开始火冒三丈,我赶紧打住话题。当一个情绪化的时候,这时候讨论是无意义的,他已经陷进去了,在自己的世界里出不来了,他只知道赚钱,从来没想过提升自己的技术水平,这就很可怕。


所谓的“穷人思维”,就是说他走的每一步都非常短视,没有任何长远打算,走一步看一步,做事全凭运气,全靠个人有限的经验,这就很危险,就很容易最后无路可走,当一个人被眼前的东西所迷惑的时候,就很难走的更远,所谓“一叶障目”,“听了好多大道理,却还过不好这一生”说的就是这种人,他从来就没有认真审视过对方的观点,而是固执己见,认为只要跟他意见不同的就是故意跟他抬杠,就是他的敌人,就可以肆无忌惮的挑衅,敌视,辱骂,他们内心自卑又脆弱,听不得一点批评的意见,哪怕是最温和的批评,他也会认为你是在针对他,遇到问题全是别人的锅,跟自己一毛钱关系都没有,没有一点责任意识,年龄上虽然是成年人了,但是心理上跟小孩没啥区别,易怒、暴躁、软弱、自卑。算了,讨论算法学习,这扯到心理学是咋回事,就此打住。


之前一位老同学,搞运维的,跟我诉苦,说他们那系统单元测试没毛病,一串起来就出问题,当时说的具体的我记不大清了,大意我就建议说让那个人试一下写个适配器,把问题解决。然后这老兄弟就说咱理论一套一套,要实践如何如何。把我逗乐了,这都是基本功呀,不是理论一套一套的,就是你不懂的话,就两眼抓瞎,网上到处搜答案,到处问人,从CSDN找答案,十个答案九个错,七个都是在复制粘贴别人的答案,也就是自个都没明白呢,也不实际玩一下,就直接人云亦云。


像设计模式,GOF23,但凡上点心,这个不可能不学,最基本的那几条原则起码心里要有数,SOLID之类的,不然你设计的时候一通瞎搞,只顾眼前,不考虑需求的可能的变动,一通“if-else"交任务式瞎搞,就会出现问题,后期一旦需求发生变化,要改你这个工作量就很大,属于是人为制造困难。要是一大堆这样的选手来搞,那必然就是屎山堆叠,难以维护,又不敢动,谁知道动了会出现什么”灵异事件“。


没人掌握整个系统的全部细节,不像硅谷好多老程序员,就5、60岁的那帮大爷,那叫一个强,人家是真的掌握每一处细节,你把他辞了,别人来了也接不了他的活,回头你还得把人请回来,给人涨一波工资。毕竟太复杂了,越到后面越复杂,越不敢轻易改动,但是人家就无所谓,各个细节全公司没有比他更清楚更了解的,动个小手术,动个刀子啥的,这不easy得很。


科班学生其实问题也不少,就是盲目自大、自卑的情况比较突出,各种造神呀,互捧臭脚的现象比较严重,说他谦虚吧,一言不合就让人“show me your code",他不把自己的代码贴出来给人看,到处让别人”show code",真的就是学会两句名人名言,就跟个鹦鹉似的,不知道自己叫啥了。一个不看课本不思考的混子,有人问了个课本上的简单问题,给人一答就嘚瑟得不知道自己姓什么了,还道德绑架别人为啥不帮群友,真的很搞笑。


课本上基础得不能再基础得东西,不看书,到处问人,这种混子,我要是他老师,早让他退学了,这种程度别学了,赶紧进厂子,这种“大聪明”学生真的不敢要,人家问问题是真的遇到难题了,实在自己解决不了,独立思考,查书,网上搜帖子,各种方法都试过了,解决不了人家才问,他这连书都不翻,网上随便search 一下的东西他到处问人,是该夸他“勤奋好学”呢?还是该骂他又懒又蠢?别人的时间都是废铁,就他的时间是金子是吧?


leetcode,其实社区环境还好,氛围还行,没有啥互相诋毁,踩踏,谩骂之类的事,毕竟大家都是文明人。就是刷题圈真的现在风气全给带坏了,各种攀比,各种歧视,各种撕x,各种抱团站队,已经在向饭圈靠拢了。知道的是做了几道计算机奥数题的学生,不知道的还以为进了某个流量明星的饭圈打榜群了,就做几道前人已经做了无数遍的题,这都能做出优越感来,真的令人匪夷所思。一个学生,一个打工人,不好好学习,想着提高技术的技术水平,整天为几道题跟人撕x,这不吃饱了撑得。


leetcode的题解区一大堆题解,人家就是不看,就是不思考,就是要进群问人,显示“自己谦虚好学”,没办法呀。这个本来就是重复做做题,增加增加熟练度,毕竟就是练一下手感的事,没啥了不起的,也不是啥值得骄傲的事,没见过那个考场的学生做完题以后满教室咋呼,到处乱跑,给人竖小拇指的,这种要是在现实中肯定会被认为精神不正常的,得赶紧送医院治疗。网上吧,小朋友还是太多了,主要现在国家提倡减负,作业布置的还是太少了,让他有时间在网上跟人对攻。


说实话,这种计算机奥数,也就是打打比赛,跟lpl英雄联盟职业联赛,kpl王者荣耀职业联赛没什么区别。就提高一下熟练度,指望靠这个拿图灵奖还是想太多了,算法最重要的是这种思维,有这个东西,工程上遇到问题了,解决起来不困难,如果把时间都浪费在对技巧的重复性上面,那根流水线工人的工作没啥区别,对流水线工人有用的就是熟练度,按件计算工资,做的越多赚的越多,但是这样肯定出不来计算机科学家,比如Edsger Dijkstra和Donald E. Knuth这样的人。


曾有位朋友跟我讨论这个问题,说这些人都是科学家,我们工程师不需要搞发明创造创新,拿着别人的东西直接用就行,我是非常反对这种观点的。工程师不需要创新吗?工程师如果没有自己独到的地方,那他跟工人有啥区别?当一个理论功底扎实,实践经验丰富的工程师,这个人要是还有一双善于发现问题的眼睛,能够发现问题,并研究出巧妙的解决方案,这样的人难道不是人才吗?一个人就不能既是工程师又是科学家?还是说科学家只负责理论研究,只负责创新,工程师只管埋头干活就行?这样的话,有没有可能科学家的理论变成了空谈,因为他没用工程经验作为底子,而工程师则蜕变为大号工人,因为他不需要思考。


其实现在这种状况,挺悲哀的。就是说算法没有真正变成学生的知识,而是变成一种脑力游戏之类的东西,变成了进入所谓大厂的敲门砖之类的东西,就是已经僵化到这个程度了,完全丧失了其本来的东西。对网上搞算法培训的,和很大一部分学生来说,算法这个东西其实已经被异化了,完全被工具了,成为了“无用”的“大厂入场券”,然后他去了给人搬砖,就说这个东西没什么卵用,本质还是没有学会算法,过分注重技巧性,思想是一点都没有掌握。“题海战术”绝对是最笨的学习方法,庸才可以通过背原题跟天才同台竞争而不落下风。


如果你真的对算法感兴趣,从工程上去玩,去看,你会发现很多有意思的,绝不是说会做几道计算机奥数题就算是会算法了,那太小儿科了,真正的大科学他大概率就是找个一个工程上的难题,然后设计出一种非常巧妙的方法,把问题给解了,然后这个就是他发明的算法,就是这么个事,既考验基本功,考验阅历,工程经验,还有设计能力,算是一个人的综合素质方面的考察吧。


学算法其实语言无所谓的,只要你把算法思想掌握了,用什么语言实现真的无所谓,就怕你买椟还珠,把时间浪费在工具上面。然后书的话最好还是有英文的直接看英文,这样既学好了英语,也学好了算法,刚开始肯定有点吃力,习惯了就好。


《剑指offer》起码第一本一定要看,认真看,多看几遍,很重要,何海涛先生是教你如何思考呢,你把他这套学会,做题也就那样,不要只做题不看书,这是错误路线,这会让你把大量时间浪费在技巧性的东西上面,没有任何意义。这本书第一本的地位就相当于《孙子兵法》在军事理论学科的地位,你说重要不重要,你把这个彻底搞明白,相当于你手握《孙子兵法》,带兵打仗那不跟玩似的。这个书的第二本可以看,能掌握一些技巧,比如双指针,哨兵节点,哈希优化减少重复计算,哪些时候需要压栈,哪些时候得用队列,各种dp套路,什么背包呀之类的。但是这些东西知道就行,练几道题就会了,不要把时间和精力浪费在这些技巧上,你要明白什么是瓜?什么是芝麻?弄不明白就会事倍功半。第一本书用c++写的,第二本书用java写的,其实无所谓,github,leetcode,gitee,到处都是《剑指offer》,什么语言写的都有,毕竟这等神书,它里面的东西肯定是非常泛滥的,遍地都是。


《程序员面试金典》,前谷歌的人写的,北美程序员必读的一本书,跟国内《剑指offer》的地位是相当的。你最好把英文版的找来看,英文名叫《Cracking the Coding Interview 》,可以去网上找找看,或者直接把中文版扔了,学习数据结构的过程中顺带学英文,不折腾,英语对一名程序员来说是必备的一项技能,起码要能看懂文档,不然你readme,quick start都看不懂,整天把时间浪费在国内培训班水平的二手资料上,这就得不偿失了,英文要扎实,不要求跟老外流畅对话,但是人家写的东西你得看懂,这是最最基本的要求。


从Amazon出来的人写了一本《Programming Interviews Exposed Coding Your Way Through the Interview》,你直接去Google搜就行,跟上面这本差不多,国内没翻译过来,书有点老了,但是很经典,这本书可以好好看一下。


左程云那本《程序员代码面试指南》这本书其实很像一本习题集,但是题目全是左程云先生自己做的,原创度就比较高,他其实讲的很细,然后最好配合他那套视频课程学,b站就有,很详细的,先看视频,在看书,你就会发现其实视频里讲的书上都有些影子,这就比较好。


《编程之美:微软技术面试心得》,习题集,很经典,可以好好看看。


王争的《数据结构与算法之美》偏实践一些,这本书好的地方就是能把算法跟实践结合起来,既给你讲理论,又结合实践,王争先生作为前谷歌工程师,工程的底子还是不错的。这本书其实就是之前极客时间的一个专栏,对部分内容进行了扩充,你也可以直接去极客时间去试听一下他的课,买不买我相信你自有判断,我不能替你拿主意,其实左程云先生那套免费的课程已经很好了,极客时间这个课程我只是给你引申一下。


刘汝佳先生和陈锋先生的《算法竞赛入门经典》这一套书是专门打竞赛的入门书,口碑相当不错,用c/c++语言写的。陈小玉女士的《算法训练营》也是偏重于竞赛的,用c++写的。


至于一些公众号主写的一些书也可以参考,但是基本都是偏重技巧性的东西,看看就好,别沉迷。打游戏要适度,做计算题奥赛题也要适度,沉迷就有害了。如下:《代码随想录》、《算法通关之路》、《labubadong的算法小抄》。


说句题外话,如果你数学底子好的话,可以直接上《算法导论》和高司令的《计算机程序设计的艺术》这一套,不要怂,直接干他,你能把这两巅峰选手干趴下。什么BAT,这个段位的选手可以直接略过了,直接去FAANG,现场表演什么叫“那年我双手插兜,不知道何为对手”,对面直接投降,还面个啥,人家就一个“水滴”就可以直接干趴下你那三千艘恒星级战舰,还有必要打吗?


Edsger W. Dijkstra写了本《编程的修炼》,可以看看,大佬写的,这个人真的牛。百度百科粘的,成就:

1.提出“goto有害论”;

2.提出信号量和PV原语;

3.解决了“哲学家就餐”问题;

4.Dijkstra最短路径算法和银行家算法的创造者;

5.第一个Algol 60编译器的设计者和实现者;

6.THE操作系统的设计者和开发者;与高德纳并称为我们这个时代最伟大的计算机科学家的人。


如果你计算机基础扎实的话,你肯定知道什么意思,这一堆,计算机领域很重要的东西,印在课本上的,这个老头一个人搞出来的,你不好奇他怎么搞的?那就看一下人家的书,主要是好好学学思路,好好看看他研究工作的心路历程,这个很重要,学会了就是你的,完全掌握,吊打同龄一帮混子,跟玩似的。


《柔性字符串匹配 》(Gonzalo Navarro, 纳瓦罗, Mathieu Raffinot, 拉菲伊诺特) 能看尽量看吧,名字就能看出来,讲字符串的,数学好好学。英文名《Flexible Pattern Matching in Strings Practical On-line Search Algorithms for Texts and Biological Sequences 》。


其实还可以往深了延伸,比如DP(动态规划)是从哪里来的?运筹学,那么你可不可以去找一本运筹学课本,看看人家到底在研究什么?在解决什么工程上的具体问题,这个好不好?不要整天沉迷于“偷房子”,“买卖股票”,“背包放东西”之类的智力游戏,算法不是什么智力游戏,而是现实中具体工程问题解决方案的抽象化,你把这个当智力游戏玩你就载进去了,出不来了。没必要通过这个显示自己智商高,没意义,说实话人跟人的智商真差不了多少,就是一个习惯问题。正常人谁会觉得“最强大脑”那些演员是什么天才、学霸之类的?天才、学霸就是纯靠记忆力的?一个人之所以被称为天才,一定是他在他所在的领域做出了巨大的贡献,解决了什么大问题,难题,而不是说他参加了什么低水平的靠包装人设、讲故事、贩卖焦虑的三流综艺节目成为天才,要搞清楚这一点。


再延伸,去看几本经典的自然科学读物,我专门写了一篇文章介绍这个,这里不再赘述,你翻过去看就行。

最后,哲学史看一下,就研究研究那些人的思考方法,分析和解释问题的思路,这很重要。不了解哲学,不知道苏格拉底,遇到问题只会追求所谓的“标准答案”,缺乏更深入的思考,就入不了科学这道门。


最后这两个是很实用的东西,不要觉得跟算法无关,算法你不就是解决问题的方法嘛。那多研究研究,把别人的思考、分析、解释的这些东西学到手,然后再多想想,未尝自己搞不出来一个,要敢想,不要害怕,中国的很多小孩就是胆子小,内向,这个不太好,很多东西思路打开了也就那样,就怕自己给自己设限。


省流版


先看视频听思想,再做题,同时看书理解。看书先找英文的,直接看英文,算法英语同时学,提高英语水平,有利于阅读文档。

  1. leetcode计算机奥数题适当做,切勿沉迷,沉迷奥数跟沉迷游戏一样,都有害。

  2. 学习算法和数据结构,不要纠结语言,重思想轻工具,切勿本末倒置。

  3. 优先看讲思想的书:《算法4》、《剑指offerI》(国区优先这本)、《程序员面试金典》(美区优先这本),其次看讲技巧的书:《程序员代码面试指南》(原创习题集,跟吉米多维奇差不多,有那个味)、《编程之美:微软技术面试心得》、《剑指offerII:专项训练》。结合工程的:《数据结构与算法之美》 打比赛的:《算法竞赛入门经典》、《算法训练营》、《趣学算法》,听一句劝,玩玩就好,别沉迷 其他技巧类的(公众号主作品):《代码随想录》、《算法通关之路》、《labubadong的算法小抄》

  4. 数学底子扎实的:《算法导论》、《计算机程序设计的艺术》,彻底学会之后,其他的可以扔了,两位业界大牛写的东西,这你都能彻底领悟,其他的差不多也就是小儿科了

  5. 更深层次。学习大牛思考研究的过程中的思想、方法、分析手段、解释手段:《编程的修炼》 深入研究字符串:《柔性字符串匹配》,远离DP智力小游戏,直接玩真的:《运筹学》(这本书很厚,不要怂,干他)

  6. 准备开宗立派,自个搞一个算法:各种自然科学专著,哲学专著, 可能这些还不够,至于还缺啥,自个探索,能力有限,就帮到这了。挂上咱写的专栏链接:自然科学入门导论(刷高分过考试者勿来):https://zhuanlan.zhihu.com/p/654047717


视频教程推荐:

1.左程云 https://www.bilibili.com/video/BV13g41157hK/?spm_id_from=333.337.search-card.all.click&vd_source=2d099601dad8d16af7236b20e0304a8c

这一套已经很nice了,教真本事,从白板画图给你讲清楚,不玩虚的,还是很好的。白板画图这套能力好好学一下,学会了你就能直接抓核心要点,直接讲,不需要浪费时间去做花里胡哨的PPT了,二、三流庸才必备工具,不要玩这个,看似高大上,实则花架子,不实用


2.王争 (收费的)https://time.geekbang.org/column/100017301 加个题外的,碰巧遇到,大牛讲经验 左耳朵耗子(收费的) https://time.geekbang.org/column/100002201?tab=catalog 这个跟算法无关,可以听听


3.MIT的《算法导论》,数学强,有信心,就干他,不要怂 https://www.bilibili.com/video/BV1Tb411M7FA/?spm_id_from=333.337.search-card.all.click&vd_source=2d099601dad8d16af7236b20e0304a8c


4.网易云课堂的《算法设计与分析》哈工大的课 https://mooc.study.163.com/course/1000002012?_trace_c_p_k2_=8837dc5341d344e690a10340dd102147#/info

没了