算法學習


  不得不說,有時候無知是福,看到一點有趣而深入的東東,就能感受到神奇。越是咱們熟悉的東西,每每倒是咱們進一步理解深入的障礙,而之因此是障礙是咱們並不知道這個是咱們理解問題的障礙。困惑中的每一次豁然開朗每每是從一點一滴的咱們已經成爲慣性思惟中開始。越是深入的原理,每每越是簡單強大。就像愛因斯坦打破牛頓給咱們原有的世界觀同樣。對於一個打破常規,讓你從新理解問題的最簡單的方法就是把你整個思考的前提否認。而帶來的結果就是咱們看問題的角度,層面有了更大的擴展。因此,有時候知道的太多反而不美,作一個白癡也很幸福。html

  哎,又無病呻吟了半天。之因此有上述感想。還得感謝本身的同窗。因爲我沒有看過MIT的經典課程《算法導論》而被鄙視,並且更無語的是,個人理由是「聽不懂,若是有老師的課堂發音的記錄」,而事實上。這個MIT早就提供了,爲了照顧想我這樣的聽力很差的傢伙。好吧,我是個白癡,不過就像上面講的,白癡也有白癡的幸福。這個假期,無聊的時候,不只能夠看《愛情公寓2》也能夠屢屢本身的數學常識了。:)面試

  《算法導論》是一名研究算法設計的課程。設計算法,咱們關心的主要是2個方面,一個是性能,另外一個是資源花費。固然,咱們重點的是性能,咱們老是但願咱們的程序跑的更快。那麼學習算法到底有什麼用呢?這是一個經典的問題。Charles Leiserson 是這樣給咱們解答的。首先,列舉了一大堆在實際編程中比性能更重要的東西:可維護性,模塊化,功能,用戶體驗等等。特別是用戶體驗,那麼既然有這麼多的東東比算法重要,那麼爲何咱們還要學習算法呢?算法

  • 算法決定了可行仍是不可行。

  在一些實時的狀況下,好比機器人等嵌入式設備,咱們不夠快,那麼就沒有意義,若是咱們用了太多的內存,一樣不行。因此,算法這個東東,老是在咱們計算機領域的最前沿部分,如人工智能,搜索引擎,數據挖掘。若是咱們是在作10年前就已經實現了的東西,那麼性能的確在一些狀況下已經不重要了。可是,若是想作一些別人沒有作過的東西,真正的實現從無到有的過程。那麼其中遇到的絕大多數問題都是,數據太複雜了。沒有能力在有限的資源下找到答案。這也就是爲何叫計算機科學,而不是計算機工程。(固然科學這個和名字是無關的,好比物理,歷來沒有那個學校叫個什麼物理科學什麼的。:))。不得不說,MIT的目標是爲世界培養leader,而咱們那破學校是爲了培養farmer(這裏並無不敬在裏面,並且事實上,作一個farmer挺好的,每一年坐在家裏,收個房租,年底村裏再分個幾十萬,比那些城裏白領好多了在物質上)。其實也不那麼絕對,非要改變世界,只要是以前沒有作過的程序,咱們在實現以前,首先思考的必定是算法。其次,則是對他不斷的優化,完善。編程

  對絕大多數的剛剛參加工做的同窗,每每不能體會到整個產品的建立過程。參與的僅僅是完善,算法的設計或是大致設計已經完成,因此感受不到算法的存在。而匆匆下了學校白學的定論。而隨着工做時間變長,總會遇到沒有或是不能直接利用原有設計的東東,那麼算法也就體現出價值了。設計模式

  • 算法是一種描述程序行爲的通用語言。

  咱們能夠經過算法去描述程序的運行流程,在任何地方。他不只能在實踐中獲得體現,也能在理論中獲得證實。並且可以獲得你們一致的見解。而這是別的永遠沒法作到的,好比用戶體驗,每一個人都有本身的想法,咱們不可能讓全部人都滿意咱們的設計,而算法卻能夠作到,由於快就是快。放到計算機上一跑結果自知。別人沒法擊敗你,即使是再挑剔的對手,只要你足夠出色。而可以知足這樣條件的前提就是,算法是一個如此通常化,基礎的東西。就像Charles Leiserson 所講,算法就像錢,你能夠用錢去買吃的,喝的。而衡量這些花費的就是錢的數目。在計算機上,則是,選擇一個這樣的策略,須要花費多少。選擇另外一個策略,須要花費多少。而衡量這2個選擇誰的花費多呢?是算法。模塊化

  算法在計算機中的地位,就和數學在全部理科學科中的地位同樣。我曾經問過個人數學老師一個問題,他的回答讓我直到如今還記憶猶新。「老師,數學在您眼中是什麼呢?」「數學是全部理科中是最奇妙的一個。由於他能夠獨立於其餘任何學科存在而其餘學科離開不了數學。」是的。可以想象物理化學離開數學以後是什麼樣子麼?可是數學爲何可以獨立存在?是由於他構建了一門語言,一門偉大的語言。使用這門語言可讓知識在任何領域中環繞,學好數學就好像有了一張無限透支的通用支票,能夠在任何地方花費(黃金?)。做爲一個可讓這麼多地方都通用的緣由中最重要的就是,他是超級穩定的。是一個說一是一的世界。一個公平的世界,絕對的世界(固然,如今數學這個概念也不許確了,這個充分體現了哲學思想,有正必有反啊:P)。他所肯定的東西的結果是確定的。沒有歧義,並且不隨時間變化而流動。好比,咱們真實世界中交流的語言,好比「忽悠」,「猥瑣」。等等。不少詞義,隨着時間的變化而改變了。使得不少年紀大的人,和咱們這年輕人在交流上就產生了隔閡。而咱們最熟悉另外一個例子就是文言文,特別是其中的一些扭曲的字。但數學這種基礎類學科是不會的。至少在一個能夠預見的範圍是穩定的,沒有地域限制的。因此,數學才能站在人類科學發展的最前沿,他的每一次前進的一小步,都能改變世界。這就是數學之美。一樣也是本身可以讓絕大多數人接受的最大障礙。因爲他改變的太慢,並且枯燥。絕大多數人沒法深刻的理解。當用世俗,腐爛,充滿銅臭,功利的眼光看待純淨的數學世界,必然發現數學無用。並且,這的確是事實,由於大部分人,都不可能成爲改變世界的傢伙(這裏的確不許確,由於改變世界話題太大,修理地球一樣也是改變世界。)。性能

  算法,一樣爲咱們計算機構建了一個純淨的世界。一個說一是一的世界,他所肯定的,沒有可以反駁的。固然,就和學習數學同樣,咱們不是去成爲數學家,學習物理,不是去成爲物理學家,而後去作哪些可以改變世界的東西。學習這些基礎類學科的重要在於,他提供了一個讓咱們和那些站在人類史上最頂尖的傢伙們交流的語言,從個人角度來看。若是沒學好數學,可以和牛頓,愛因斯坦交流麼?沒有學好算法,可以和高爺爺交流麼?做爲一個普通人,咱們只要學習到他們身上的一點點,也就足夠了。固然,這不是對全部傢伙都有效,有些人老是想,和那些老傢伙有什麼好交流的,給我一個周杰倫的簽名吧。:)學習

  • 學習算法還有一個緣由,是的,就是興趣。這個傳說中最牛X的老師。

  喜歡算法,沒有別的緣由,是的。我就是喜歡比別人快速的感受。喜歡數學,是的。由於大部分人數學很差。因此我就喜歡數學。迎難而上,哥就是喜歡作別人作不了的東西。是的,雖然聽上去很牽強,並且比較扭曲。比較符合印象中90後的想法。不知道90後是否是能產生更多的數學家呢?優化

  讓咱們回到咱們的算法上,既然咱們這麼關注性能,那麼什麼是影響性能的因素呢?搜索引擎

  對於一個計算機外行來講,首先就是計算機硬件自己的運算能力。多一個超級牛的CPU,超大的內存,固態硬盤。確定運算快。的確,若是你拿一個超級計算機和地攤上買的一個小的計算器比運算能力。這個實在是一個很顯然的結果。是的,因此,咱們有些狀況下,須要思考在相同條件下,到底哪一個算法的性能更高。這比較的是相對速度。可是咱們卻不能忘了這一點。有時,咱們想使用一些很通常的計算機,經過優秀的算法,來戰勝那些擁有更高硬件的那些傢伙們,而咱們則必須關心算法性能的絕對速度。那麼咱們該如何描述這些看似互相矛盾的東西呢?不要忘記,算法但是基礎啊,咱們要的是一個確切的答案。咱們如何給出一個確切的答案,而這個答案無論是超級計算機,仍是普通PC都可以支持呢?這就是算法中最重要的一個概念,甚至是一切分析的大前提,一個能夠把這些複雜的因素都考慮在內(或是都不考慮在內)的東東轉換爲能夠用數學分析的對象。這就是漸進分析。

  漸進分析的基本思想是:

  • 忽略硬件結構
  • 不使用真實世界的運行時間,而是關心運行時間的增加速度爲對象

  漸進分析是一個很是龐大的概念,咱們最熟悉的,也是大多數本科院校教咱們的就是Θ,O,Ω等等相似的這些符號。這裏只從Θ開始。

  對一個初學者,Θ-notation是比較容易接受的。對一個多項式,咱們只須要刪除掉全部的低次冪項,忽略掉常數,係數這些次要因素。就和Charles Leiserson 所講的。這個描述,是工程方向的描述,並非嚴格的數學上的定義。而對像我這樣的小白來講,最大的誤解就是把他當成了數學上的嚴格定義而產生了極大的困惑。

  這個是一個至關經典的圖,當n趨於無窮大時,Θ(n3)總能幹掉Θ(n2)。無論是一樣的硬件設備,仍是不一樣的硬件設備。只是在不一樣的設備下,不一樣的算法下,咱們有了一個不一樣的係數,低次冪項,和常數。可是,咱們關心的是他隨着數據輸入長度的變大而產生的增速。當n超過n0時,任何的次要因素都是浮雲了。咱們就能夠說Θ(n3)被Θ(n2)幹掉了,即便Θ(n3)的硬件要比Θ(n2)好不少,在一開始的時候效率有多高。

  這是一個偉大,cool的概念。是的,他完美的既知足了咱們追求的絕對速度,也能知足咱們追求的相對速度。能夠說,這給了咱們繼續學習算法的動力。可是,事實上,在實際開發中,咱們有時候卻使用那些在學校中認爲是效率低的算法。難道這個理論錯了?固然不是,錯的是咱們,咱們忽略了一個很大的前提,n0。在咱們多數開發過程當中,不多接觸那些海量數據的運算。咱們的運算多數是在一個較少的數據上下浮動,這個也能夠說咱們的硬件,資金,產品,根本不須要咱們整那麼大的數據。也就是n0,咱們根本達不到。事實上,只要是有腦子的,看到這個圖,在小於n0的前提下,都會作成正確的判斷。但對於剛剛步入IT的廣大學生,卻老是犯下屁股決定腦殼這樣愚蠢的選擇。而這其實,就是作科學和作工程師的最大區別。理論和實踐相互掰手腕的結果。

  這幾天,挖老趙的「墳」,找出了這麼一篇。寫程序時該追求什麼,什麼是次要的?裏面有一段十分搞笑的代碼,之因此這樣說,是由於我本身也寫過這樣的代碼。想一想真是dt啊。回想事發現場,我記得是我看了個什麼相似《面試寶典》東東,有一些題考察交換元素,事實上,你能夠找到一大堆的,並且是更精妙的去交換2個元素。看到以後,如獲至寶。只要是2個元素要換位置,就用。站在作科學的角度上看,這無可厚非。可是若是站在工程的角度來看。這就是明顯的多此一舉。每每花費80%的精力在提升%20的性能上,而不是去花費20%的精力提升80%的性能。這一樣是剛剛步入IT的廣大同窗的問題。作科學須要嚴謹,可是在工程方面,考慮的事情很是複雜,多。咱們必需要關注在覈心,關鍵的部分。這樣才能在有限的資源下,最大的作出東東來。實踐中,沒有任何項目的資源是足夠的。MS,Google都會有資源不足的時候。咱們須要學會抓住重點。固然這裏並無鄙視這些面試問題,事實上,這些問題的背後每每是考察數學思惟的基本功,而不是鼓勵你們這麼作。就像那個經典的問題,12個小球一架天平。沒有仔細,嚴謹的思考,可以想到這個東東能和排序問題扯上勾麼?神啊,萬惡的功利,給完美的數學模型批了一層邪惡的外套,使咱們在追求本質的過程當中迷失。

  有關n0的問題,不只在算法設計上,也出如今咱們的設計模式之中。《設計模式》這本神書,我是沒看過,也不敢看。但也隱隱感受到相似「設計過分」的言論。這一樣都是在理論和實踐結合上出了問題。固然,很多理論支持者,確定會說,那是由於你沒作過那麼大的項目。但事實倒是,無論設計多麼複雜的,仍是多麼簡單的,實踐和理論永遠不可能都獲得知足。Windows操做系統能夠說是一個咱們可見的最大的項目之一了。可是Windows也並非一個微內核,在內核中也綁定了很是多的「多餘」的部分。從理論上看,那無疑會下降系統穩定性,提升維護難度。可是咱們卻不能不說Windows是最成功的一套軟件之一(這個之一甚至均可以去掉)。

  固然,要想在作學問和實踐找到平衡點。這個無疑是極大的挑戰。只是分析理論,而不實踐,那麼永遠不可能成爲一個出色的工程師。除非你的目標是成爲理論科學家。反過來,若是不理論而只是實踐,不一樣的是,這個是能夠成爲一個出色的工程師。因此,這裏有一句經典的話。

If you want to be a good programmer, you just program ever day for two years, you will be an excellent programmer. If you want to be a world-class programmer, you can program every day for ten years, or you can program every day for two years and take an algorithms class.

  既然算法是如此的重要,那麼咱們該如何學呢?其實,這是一個很糾結的問題。甚至是一個雞生蛋,蛋生雞的問題。不學算法,你不會了解他,也不會認識到算法重要;認爲算法不重要,那麼也就不會下功夫去學。這就又回到一開始的那個unknown unknown上了。因此,若是準備學習算法,也就意味着選擇了一條坎坷的路。一開始特別迷茫,可是沒有別的選擇。惟有堅持,放下浮躁,功利的心態,沉浸在數學的世界中才能體會到數學的價值,數學的樂趣。也只有這樣,才能堅持到最後。

  固然,能作到這一點的,敢說體會到數學之美的傢伙,全世界也沒有幾我的。那麼,做爲一個普通人,咱們怎麼才能最大的去提升本身,更好的掌握實踐和科學的平衡點呢?這個問題,我本身也沒有答案。由於我既沒經驗又沒理論。這裏只是扯下我本身的理解,可能很偏激。

  首先應該研究下劉未鵬的不少博客內容,特別是錘子和釘子。對我這樣的新手來講,武器真的太少了。因此當撿到一個武器每每過於興奮而忽視了這個武器的使用前提,每每殺雞用牛刀,並且還達不到積極的效果。就是由於咱們拿到錘子以後,全部東西看上去都像釘子。因此,咱們惟有擺正心態,深刻了解擁有的武器,並增長更多的武器,見更多的市面,才能坐懷不亂,達到手中有錘,心中無錘的最終境界。

  一個稍微實際的例子。對像我這樣的菜鳥來說,大部分都會遇到這樣一個問題。並且困惑好久好久。「堆排序爲何比快速排序在大多數時要慢呢?」事實上,形成這個問題的主要緣由(對我)就是,沒有理解明白Θ-notation。那些被忽略掉的次要因素,固然還有更重要的是數學上對機率的薄弱理解。而後咱們會再映射出一大堆的數學基礎知識,而後大部分人死在沙灘上(真的,這是我從小以來最大的遺憾,就是沒有學好幾率,而形成這個的緣由竟然是,這些題目初學時每每是用平常用語出題,而因爲本人語文太差,總不能理解清楚題意,而對這類題目產生了極大的抵觸,可見小朋友們千萬不要偏科:P)。從科學的角度去,徹底能夠證實這個問題,可是付出的代價就是沒有碩士以上的數學能力的玩家,沒有機會理解到那個層次。那麼,其實咱們能夠從另外一個角度看,直接放到計算機上跑一下就能夠了麼。是的,我不是科學家,我只須要知道結果就OK了。是啊,好在咱們處在一個和諧的世界。讓咱們從這個龐然大物中得以解脫,因此,有時,咱們須要根據自身狀況,放棄一些東西,特別是那些比較可以經過實驗來證實的東西。

  好吧,總不能啥也放棄吧,都放棄了那到底也簡單了。這裏,我只能說,我推薦SGI STL。在我看來,這是一個結合了設計模式,理論算法與實踐最好的一個實例。他不只是開源的,代碼量也很少,命名也算規範,並且還有一本侯捷大師的著做來詮釋,幫助咱們理解,並且還能幫助咱們具體實踐過程當中規避一些錯誤。咱們每個在學校學習的算法,咱們均可以在這裏找到答案(至少能夠用來作做業拿高分對某些特別的女生),並且都會比通常大學講的深入,事實上,我認爲,大學如今的教育爲何以爲無用,不是太難太理論,而是教的太簡單了,簡單到已經沒有用的地步了,從而根本沒有實際意義。(大學聯合培訓機構,是我所見過的,比大學擴招還要搞笑的事情)好比快速排序,SGI STL作了很是多的優化來保證不管在何時,都不會退化到n2,在分的過程老是分很差時,採用堆排序。在快速排序到作最後幾步,爲了減小開銷而採用插入排序去作哪些立刻就要排好序的部分。而這些策略,並非憑空想象,均可以在高爺爺的著做中找到理論證實,以及網上的各類論文,前提是你的數學功底足夠(固然這裏實踐在前仍是理論在前這個實在是沒有討論的意義)。因此,理論不是沒有用,只是本身學的太膚淺。實踐也不是沒有用,只是本身沒有考慮那麼多的狀況,想的太簡單而已。

  固然,這個可能又會引發另外一個龐大的問題,「不要重複製做輪子」,不過這個已經大大超出這篇文章的範圍了。我本身的見解是,STL是爲了實現最基本的最通用的東東的,而實際過程當中,咱們每每有本身的特殊性。而這些特殊性是STL不可能設計時都給咱們考慮周全的。也就是咱們極可能須要擴展,重寫部分以適合咱們的須要。固然,如今離這些目標還很遠很遠很遠。

相關文章
相關標籤/搜索