大家好,我是北子哥。 經(jīng)常有學(xué)妹問我(其實(shí)學(xué)弟也愛問): 大學(xué)應(yīng)該更偏向技術(shù)還是算法和數(shù)據(jù)結(jié)構(gòu)這類。 大家都是成年人了,這還用選嗎? 當(dāng)然是兩者都要重點(diǎn)啃下來呀,算法和技術(shù)相輔相成的,一定不要有二選一的想法! 算法和數(shù)據(jù)結(jié)構(gòu)可以說是技術(shù)(包括MySQL、Java、Redis、操作系統(tǒng)這些)的基石: 我當(dāng)時(shí)大一也是覺得數(shù)據(jù)結(jié)構(gòu)沒啥用,哪有學(xué)個(gè) JS、CSS 寫個(gè)漂亮的網(wǎng)頁炫酷? 什么算法,明明有 qsort 還要學(xué)快排、堆排? 這玩意有 qsort 快嗎? 我直接一行就排好序了,你還要寫十幾行,真菜呀! 那時(shí)候以為的技術(shù)就是使用各種組件、調(diào)API,比如 Map: 但是越學(xué)到后面心里越?jīng)]底,因?yàn)檫@些東西對(duì)自己都是黑盒子。 所以如果數(shù)據(jù)結(jié)構(gòu)與算法掌握不好,那么這些 API 對(duì)于我們就是一堆的黑黑子,連什么時(shí)候用 Map(紅黑樹實(shí)現(xiàn))、什么時(shí)候用 HashMap 都分不清。 Redis 這種組件,難道只需要了解如何get、set 就是算是掌握了嗎? 那肯定不行,實(shí)際上想要要用得好,得要了解 Redis 底層的那些數(shù)據(jù)結(jié)構(gòu),比如簡(jiǎn)單動(dòng)態(tài)字符串(SDS、鏈表、字典、跳躍表、整數(shù)集合、壓縮列表,才能選擇適當(dāng)?shù)拇鎯?chǔ)結(jié)構(gòu)。 如果要問我大學(xué)什么最后悔?那肯定是沒有從大一就開始好好學(xué)算法,去打 ACM。 現(xiàn)在還在大一、大二的同學(xué)還不抓緊機(jī)會(huì),別給自己留下遺憾。當(dāng)然,不打 ACM,我們也是能夠?qū)W好數(shù)據(jù)結(jié)構(gòu)和算法的。 數(shù)據(jù)結(jié)構(gòu)和算法你能在任何計(jì)算機(jī)領(lǐng)域里看到,比如在編譯原理中寄存器的分配會(huì)用到貪心,死代碼檢測(cè)與消除會(huì)用到圖論里不可達(dá)的知識(shí);操作系統(tǒng)進(jìn)程、線程調(diào)度會(huì)用到多級(jí)隊(duì)列和調(diào)度算法;組成原理中 Cache 的替換會(huì)用到 LRU、FIFO 等算法;開發(fā)必備的數(shù)據(jù)庫也離不開B+樹、LSM 等數(shù)據(jù)結(jié)構(gòu)和查找算法。 很多時(shí)候我們需要的算法都被封裝到編程語言的基礎(chǔ)庫里了,以至于很多同學(xué)會(huì)覺得算法離我們太遠(yuǎn),其實(shí)不是的。 所以學(xué)習(xí)算法有助于我們根據(jù)應(yīng)用場(chǎng)景選擇最合適的數(shù)據(jù)結(jié)構(gòu)。 日常開發(fā)中也一定離不開算法,比如小北最近工作中涉及的某種嵌套 TLV(Tag-Length-Value)結(jié)構(gòu)編碼的解析,就需要用到遞歸、多叉樹等知識(shí)。如果不學(xué)習(xí)算法,那么程序中只能見到大量的 if/else、while/for。。。 可以說不學(xué)算法的工程師一定不是一個(gè)優(yōu)秀的工程師。 再來說操作系統(tǒng)、編譯原理,這些里面也是蘊(yùn)含著各種數(shù)據(jù)結(jié)構(gòu)與算法的,就拿編譯原理來說。 一、編譯原理遇見算法當(dāng)你學(xué)完有限狀態(tài)機(jī)以后,你會(huì)發(fā)現(xiàn)以前覺得很牛逼正則表達(dá)式似乎自己也能用 DFA、NFA 實(shí)現(xiàn)一下了。狀態(tài)機(jī)的思想在編程中很多地方都用得上。 比如解析 HTTP 協(xié)議,如果沒學(xué)過狀態(tài)機(jī)思想,你可能會(huì)一行行的 if/else 去做解析,這里最麻煩的地方在于,if/else 需要提前將 HTTP 頭部字段都接收到再來判斷,而我們知道 HTTP 基于 TCP,而 TCP 是流式傳輸,所以你很有可能是幾個(gè)字符一組組接收到的,這個(gè)時(shí)候用 if/else 寫出來就很難看了。 而用狀態(tài)機(jī)編寫起來代碼就會(huì)非常優(yōu)雅。狀態(tài)的轉(zhuǎn)移是由規(guī)則驅(qū)動(dòng)的,接收到一個(gè)字符就判斷一個(gè),非常的方便。 繼續(xù)學(xué)完語法分析,你會(huì)掌握遞歸下降分析這樣非常重要的思想,你可以使用遞歸下降快速的實(shí)現(xiàn)四則運(yùn)算計(jì)算器。 如果不用遞歸下降你可能需要先中綴表達(dá)式轉(zhuǎn)后綴,然后求值,這是我們大一數(shù)據(jù)結(jié)構(gòu)課寫的,當(dāng)時(shí)用棧寫的,有點(diǎn)麻煩。后來學(xué)完編譯原理,又用遞歸下降重寫了一遍,區(qū)區(qū)幾十行代碼遍搞定。 還有一類場(chǎng)景在實(shí)際開發(fā)中的用的很多,比如淘寶、京東這樣的電商,它們的營銷規(guī)則有很多,比如滿減、直減、跨店等等,這樣的規(guī)則是不可能寫死在代碼里的。 那是怎么做的呢? 一般會(huì)實(shí)現(xiàn)一個(gè)配置系統(tǒng),并設(shè)計(jì)一個(gè)DSL(領(lǐng)域特定語言)來表達(dá)這些規(guī)則,將規(guī)則直接配置到系統(tǒng)中,這樣可以非常方便的修改,那么如何在代碼里去解析 DSL 定義的規(guī)則呢?這就需要為 DSL 寫一個(gè)語法解析器,這里就會(huì)用到語法分析的方法。 DSL(Domain Specific Language),它是一種用于某個(gè)特定領(lǐng)域的程序設(shè)計(jì)語言。這種特定于某個(gè)領(lǐng)域是相對(duì)于 C、C++、Python 這種通用語言而言的,通用語言可以在各個(gè)領(lǐng)域使用,我們熟悉的大多數(shù)程序設(shè)計(jì)語言都是通用語言,它們都是圖靈完備的。 像我們平常經(jīng)常使用的 JSON、SQL、HTML 這些都算是一種 DSL,你甚至可以嘗試用遞歸下降去寫一個(gè) JSON、XML 解析器,這比寫電商網(wǎng)站更有價(jià)值的。 繼續(xù)往下學(xué)你會(huì)了解到抽象語法樹 AST 如何生成、如何轉(zhuǎn)化為中間代碼、如何對(duì)中間代碼優(yōu)化、最終又是怎么生成機(jī)器指令的。 你會(huì)看到貪心算法在寄存器分配中的應(yīng)用,也會(huì)看到圖論中的可達(dá)性分析又是如何實(shí)現(xiàn)死代碼消除。 二、CS 基礎(chǔ)課所以無論是操作系統(tǒng)、計(jì)算機(jī)網(wǎng)絡(luò)、編譯原理這些基礎(chǔ)CS課程,還是MySQL、Redis這些中間件,都是構(gòu)建在各種精妙的數(shù)據(jù)結(jié)構(gòu)與算法之上的,數(shù)據(jù)結(jié)構(gòu)與算法必學(xué),一定要重視! 如果你有 ACM 獲獎(jiǎng)經(jīng)歷,那 BAT 是很容易進(jìn)的,但是也一定要掌握基本的CS基礎(chǔ)課程知識(shí),不能只重算法不重基礎(chǔ)。 國外可能把題刷好就能拿到offer,但是國內(nèi)不懂 OS、網(wǎng)絡(luò)這些基礎(chǔ)和一些語言八股文也是很難的! 三、CS 學(xué)習(xí)路線很多大一大二的同學(xué)其實(shí)是不太清楚到底該計(jì)算機(jī)專業(yè)該如何自學(xué),在這分享下我的學(xué)習(xí)路線吧: 我大學(xué)專業(yè)學(xué)計(jì)算機(jī)的,對(duì) CS 本科課程還算了解,也經(jīng)常了解學(xué)習(xí)國外 CS 課程。 CS 專業(yè)區(qū)別于其它專業(yè)很大特點(diǎn)就是:
比如你學(xué)了數(shù)據(jù)結(jié)構(gòu)、編譯原理、操作系統(tǒng)、計(jì)算機(jī)網(wǎng)絡(luò),如果你從事的是研發(fā)崗,那一定離不開這些知識(shí)。
不管是科班還是非科班,想要快速持續(xù)的提高技術(shù)水平,就得靠自己去鉆,尤其離不開自學(xué)。 知乎上其實(shí)很多問科班和非科班的差別在哪,其實(shí)我一直想說,你給自己充足時(shí)間去把科班的內(nèi)容學(xué)習(xí)一遍,到底還能差在哪呢? 可能唯一差別就是少了一個(gè) 計(jì)算機(jī)學(xué)士學(xué)位。 也有人把這種自學(xué)出家的叫做民科,當(dāng)然沒有任何的諷刺意思哈。 四、那么計(jì)算機(jī)專業(yè)該如何自學(xué)呢?最簡(jiǎn)單的方式就是參考 CS 科班同學(xué)的課程,比如下面這個(gè): 其實(shí)看著很多,概況起來就是(下面只涉及CS專業(yè)課):
學(xué)習(xí)的途徑就是: 多看國外/國外的 CS 名校的一些開放課程 + 看經(jīng)典的書 + 多寫代碼!?。?/p> 畢竟現(xiàn)在MOOC、Udemy、B站上學(xué)習(xí)的資源都是很豐富的。 唯一要做的就是篩選一些比較好的課程進(jìn)行學(xué)習(xí),在這里我主要推薦一些國外的計(jì)算機(jī)課程,他們很明顯的一個(gè)特征就是注重實(shí)踐。 一門課,除了理論以外,還會(huì)有配套的 Lab、assignment,而且這些老師設(shè)計(jì) Lab 都很用心的,看視頻/書 + 做 Lab,這應(yīng)該算計(jì)算機(jī)科班同學(xué)一個(gè)比較好的學(xué)習(xí)方式了,有理論也有實(shí)踐。 下面開始上干貨: 一、計(jì)算機(jī)導(dǎo)論 首先建議從計(jì)算機(jī)導(dǎo)論課程開始,推薦下面這些課程:
隨后建議學(xué)習(xí)一門語言,可以是C、Java、或Python,我推薦 C語言(當(dāng)然,也可以是Python!這不是重點(diǎn),重點(diǎn)是要多去寫,入門時(shí)提高對(duì)編程的興趣)。 提到C語言,我這里推薦國內(nèi)浙大翁凱老師的課,看過的都說好,分為兩門: 第一門是面向高考結(jié)束想提前自學(xué)一點(diǎn)編程的,叫大學(xué)先修課:C語言程序設(shè)計(jì)CAP-大學(xué)先修課 雖然叫先修課,但是覆蓋了C語言的主要知識(shí)點(diǎn),也適合大一新生~ 第二門是C語言程序設(shè)計(jì)進(jìn)階:C語言程序設(shè)計(jì)進(jìn)階 會(huì)帶你用C語言完成一些有趣的項(xiàng)目,比如一些圖形界面小游戲,先修課學(xué)習(xí)C語言語法基礎(chǔ),進(jìn)階課帶你項(xiàng)目實(shí)操,搭配使用,你就是同學(xué)中的大神! 有了語言基礎(chǔ)之后建議學(xué)數(shù)據(jù)結(jié)構(gòu)與算法: 數(shù)據(jù)結(jié)構(gòu)推薦:
算法推薦:
學(xué)習(xí)完經(jīng)典的數(shù)據(jù)結(jié)構(gòu)和算法之后就可以去刷題了。 操作系統(tǒng)推薦:
這兩個(gè)都是有視頻有l(wèi)ab的好課 還有一個(gè)非常經(jīng)典的 MIT 6.828,附帶一個(gè)xv6 lab 課程:6.828: Operating System Engineering 組成原理、體系結(jié)構(gòu):
計(jì)算機(jī)網(wǎng)絡(luò):
五、新手快速自學(xué)的方法
計(jì)算機(jī)里,幾乎都是人造的概念,大部分的東西,只要你一直深挖下去,幾乎都可以搞明白。 但是要注意時(shí)間成本,軟件行業(yè)已經(jīng)不是一般的復(fù)雜和巨大,任何一個(gè)領(lǐng)域的知識(shí)的復(fù)雜性都足夠耗費(fèi)掉我們一生的時(shí)間,所以一定要抓住主線,對(duì)于技術(shù)和知識(shí),要學(xué)通用的、流行的,可以嘗試面向面試學(xué)習(xí)。 “打破砂鍋問到底”式的學(xué)習(xí)雖然精神可敬,但性價(jià)比并不劃算。 一定要學(xué)會(huì)在適當(dāng)?shù)膶哟紊铣橄蟪鲆粚?,并且認(rèn)可這一層提供的接口,不去深究內(nèi)部實(shí)現(xiàn),了解原理即可,不必深究內(nèi)部實(shí)現(xiàn)。 比如學(xué)習(xí) HTTP,那么就先認(rèn)可 TCP 提供的穩(wěn)定可靠傳輸,而不繼續(xù)深挖 TCP 的內(nèi)容,等到學(xué)習(xí)傳輸層的時(shí)候再去深入挖掘 TCP 具體實(shí)現(xiàn)。 也就是我們常說的面向接口/抽象編程。
新手,一定不要一直看書,保持看書的時(shí)間不超過 50%,按照下面的流程:
如此反復(fù)的循環(huán)。 你好,我是小北,畢業(yè)于某末流985,前國外計(jì)算機(jī)公開課硬核 Lab 玩家,現(xiàn)職場(chǎng)萌新,微信后臺(tái)小開發(fā)。 高中編程 0 基礎(chǔ),從小白到計(jì)算機(jī),大三時(shí)通過實(shí)習(xí)和技術(shù)變現(xiàn)收入 10 W+,點(diǎn)擊藍(lán)字查看我的「編程能力突飛猛進(jìn)之路」。 編程指北 編程學(xué)習(xí)之路的好幫手、指南針~ 78篇原創(chuàng)內(nèi)容 公眾號(hào) |
|