知其所以然地學習(以算法學習為例)

其實下文的絕大部分內容對所有學習都是同理的。只不過最近在正兒巴經地學算法,而后者又不是好啃的骨頭,所以平時思考總結得就自然要比學其它東西要多一些。

問題:目前幾乎所有的算法書的講解方式都是歐幾里德式的、瀑布式的、自上而下的、每一個推導步驟都是精準制導直接面向目標的。由因到果,定義、引理、定理、證明一樣不少,井井有條一絲不亂毫無贅肉。而實際上,這完全把人類大腦創造發明的步驟給反過來了。看起來是陽關大道,實際上車馬不通。

而對讀者來說,這就等于直接告訴你答案&做法了,然后讓你去驗證這個答案&做法是可行&成立的。而關于答案&做法到底是怎么來的,從問題到答案之間經歷了怎樣的思維過程。卻鮮有書能夠很好的闡釋。就我有限的閱(算法)書經驗,除了波利亞的《怎樣解題》還算合格之外(也并非最理想),其它的(包括有名的《算法導論》、《如何解題:現代啟發式方法》、TAOCP、《Algorithms》、《編程珠璣》etc.),在思維的講述上都遠遠算不上合格(當然不是說這些書沒有價值,作為知識性的參考書籍,它們將知識整理出系統結構,極大的便利了知識的掌握,就像《什么是數學》所做的工作一樣),為什么我這么說呢,因為我發現每每需要尋找對一個算法的解釋的時候,翻開這些書,總是直接就看到關于算法邏輯的描述,卻看不到整個算法的誕生過程背后的思想。

我們要的不是相對論,而是誕生相對論的那個大腦。我們要的不是金蛋,而是下金蛋的那只雞。

為什么會這樣,其實是有原因的。

我們在思考一個問題的過程中有兩種思維形式:

  • 聯想:這種思維某種程度上可以說是“混亂”的(雖然從一個更根本的層面上說是有規則的),所謂混亂是指很多時候并不確定聯想到的做法最終是否可行,這些聯想也許只是基于題目中的某個詞語、語法結構、問題的某個切片、一些零星局部的信息。這個過程是試探性的。最后也許有很大一部分被證明是不可行的。很多時候我們解決問題用的都是這種思維,簡言之就是首先枚舉你關于這個問題能夠想到的所有你學過的知識,然后一一往上套看看能否解決手頭的問題。這種思維方式受限于人腦聯想能力本身的局限性。我在《跟波利亞學解題》中就提到了幾個例子。聯想本身需要記憶提取的線索,所以受到記憶提取線索的制約,如果線索不足,那怎么也聯想不起來。而提取線索的建立又取決于當初保存記憶的時候的加工方法(《找尋逝去的自我》里面有闡述),同時,面對一個問題,你能夠從中抽取出來的聯想線索又取決于你對問題的認識層度/抽象深度,表淺的線索很可能是無關的,導致無效的聯想&試錯(《Psychology of Problem Solving》里面有闡述)。總之,聯想這個過程充滿了錯誤的可能。
  • 演繹&歸納:演繹&歸納是另一種思維形式。它們遠比聯想有根據。其中演繹是嚴格的,必然的。歸納也是有一定根據的。在面對一個問題的時候,我們有意無意的對問題中的各個條件進行著演繹;譬如福爾摩斯著名的“狗叫”推理——狗+生人=>吠叫 & 昨晚狗沒有叫 => 那個人是熟人。就是一個典型的對問題的各個條件進行演繹的推理過程。還有就是通過對一些特殊形式的觀察來進行歸納,試圖總結問題中的規律。然而,不幸的是,面對復雜的問題,演繹&歸納也并不總是“直奔”問題的解決方案的。人的思維畢竟只能一下子看到有限的幾步邏輯結論,一條邏輯演繹路徑是否直奔答案,不走到最后往往是不知道的,只要答案還未出現,我們大腦中的邏輯演繹之樹的末端就始終隱藏在黑暗之中。而當最終答案出現了之后,我們會發現,這棵演繹之樹的很多分支實際上都并不通往答案。所以,雖然演繹&歸納是一種“必然”的推理,然而卻并不“必然”引向問題的結論,它也是試錯的,只不過比聯想要更為靠譜一些。

既然認識到,人類解決問題的兩大思維方式實際上都是有很大的試錯成分的(好聽一點叫“探索”),那么就不難意識到,對一個問題的思考過程實際上是相當錯綜復雜的,而且充滿了無效分支——在思考的過程中我們也會不斷的對分支進行評估,做適當的剪枝——因此當我們找到問題的解之后,一來思維的漫長繁雜的過程已經在大腦里面淡化得差不多了,只有那些引向最終結論的過程會被加“高亮”——我們在思考的過程中本就會不斷的拋棄無效的思路,只留下最有希望的思路。簡而言之就是最后證明沒用或者早先我們就不抱希望的一些想法就被從工作記憶中扔掉了。二來,思考過程是我們的空氣和水,而“魚是最后一個感覺到水的,我們感覺不到思維法則本身的存在,我們只是不知不覺運用它。三來,由于我們的目標是問題的解,解才是我們為之興奮和狂喜的東西,而不是求解的過程,過程只是過程,目的才是目的。這就像一個尋寶者,在漫長曲折的尋寶歷程之后,在找到寶藏的時候,他會對寶藏感到狂喜(記得阿基米德的“找到了!”嗎?)而迫不及待地要展示出來,而漫長的思考本身卻成了注腳。我們是有目的的動物,目的達到了,其它的就相對不那么重要了。最后,對于傳授知識的人,也許還有其四:感到介紹思維過程是不相干的,畢竟思維過程并不是算法問題的解,算法問題的解才是算法問題的解。然而不幸的是,忽視到達解的那個過程實際上卻變成了舍本逐末。我們看到的是寥寥數行精妙絕倫的算法,然后仰天長嘆自己想不出來啊想不出來。為什么想不出來,因為你不知道那短短數行算法背后經歷的事怎樣漫長的思考過程,如果問題求解是一部偵探小說,那么算法只是結局而已,而思考過程才是情節

既然如此,也就難怪古往今來算法牛人們算法牛,但卻沒有幾個能真正在講述的時候還原自己的思維過程的(那個“ 漁”字),手把手的教學生走一遍推理的思路,就可以讓學生獲得思維過程的訓練。金出武雄在《像外行一樣思考,像專家一樣實踐》中說寫論文應該寫得像偵探小說一樣,我很贊同。歐幾里德式的介紹,除了提供枯燥的知識之外,并沒有提供幫助人獲得知識的東西——思維(關于對數學書籍的歐幾里德式寫法的批評其實也是由來已久了,并且有人呼吁了好幾種其它的教學方法)。從這方面,我們所尊敬的一些“圣經”級書籍在傳道授業上還不如偵探小說,前者是羅列一大堆知識,后者則是闡述獲得知識的過程——推理&聯想。

然而,我們都是人,人類該有的思維形式,我們難道不是都有嗎。既然如此,思維本身又有什么需要一遍遍教的呢?

并非如此。

講述思維過程而非結果有幾個極其重要的價值:

  • 內隱化:思維法則其實也是知識(只不過它是元知識——是幫助我們獲得新知識的知識);是內隱的記憶。我們在思考的過程中覺察不到思維法則的作用,它們卻在幕后實實在在的左右著我們的思維軌跡。要將思維方法內隱化,需要不斷練習,就像需要不斷練習才能無意識狀態下就能騎自行車一樣。
  • 跨情境運用:思維法則也是知識記憶,是問題解決策略。既然是記憶,就受到提取線索的制約,這就是為什么當波利亞告訴你要“注意未知數”之后你還是不能真正在所有需要你“注意未知數”的地方都能提醒自己“注意未知數”。很多時候未知數是很隱蔽的,未知數并不會總是頭頂一個大帽子上面寫著“我是未知數”。所以很多時候缺乏對這個策略的“提醒”線索,這也是為什么你學會了在解決數學問題的時候“注意未知數”卻不一定能在解決現實生活中的問題中時刻都能“注意你的未知數”(《你的燈亮著嗎?》整本書的價值便在于此),因為解數學題和解決生活中問題的場景不一樣,不同的環境線索,在你大腦中激發的記憶也不一樣。就連問題求解中,不同的問題之間的細小差別也可能導致思維軌跡很大的不同,有時你的注意力會被一個無關線索激發的聯想吸引開去,忘記如“注意你的未知數”這樣的重要法則。而一本從思維角度來講問題求解的書則可以一遍遍將你置于不同的問題場景下然后在該提醒你的時候提醒你,讓你醒悟到“哦,原來這個時候也應該想到這個啊。”,做多了這樣的思維演習你就會逐漸從中領悟到某種共性,并將一些思維習慣得到強化,于是終于能夠在需要運用某策略的時候能適時的想起來了。
  • 對問題解的更多記憶提取線索:我們平時學習算法時幾乎僅止于“理解”,別人把一個方案放在你面前,你去驗證一下,心說“哦,不錯,這個的確可以工作”。然后就沒了。稍微簡單一點的算法還好,復雜一點的對于記憶的負擔是很大的,這就是為什么有時候我們看到一個絕妙的解法,這個解法看上去不知道從哪里來的,但經過我們的理解,卻發現是對的,我們感嘆,真巧妙,結果一些天之后,別人問起這個問題,我們說:“唉,那是個多么巧妙的算法啊,但是我只記得它巧妙,卻不記得它到底是怎樣的了。” 為什么?因為在不知其所以然的情況下,算法只是一堆離散的機械步驟,缺少背后的思想的支撐,這些步驟之間就沒有一個本質層面上的關聯(先知亞里士多德早就指出:學習即聯接)。所以就跟背歷史書也沒多大區別。然而,知道了算法是怎樣一步步被推導出來的,我們就一下擁有了大量的記憶提取線索:對算法發現過程中的任何一個關鍵步驟(尤其是本質)的回憶都可能使我們能夠自己動手推導出剩余的內容譬如你知道堆(heap)是怎樣由樸素的決策樹演化而來的,它又是為了解決什么問題的,你即便忘記了具體的細節,也可以自己推導出來。譬如你知道KMP算法的本質在于消除回溯,至于如何消除回溯卻并不是那么難以推導的,所以即便忘了也可以借助于大腦的邏輯演繹能力再現出來。譬如你知道Tarjan算法其實只是從后序遍歷經過兩個優化調整而來的(其中并査集的使用其實只是優化手段——為了能夠迅速判斷祖先節點是誰——而非算法本質——當然,算法設計的主要任務本來就是通過問題條件中蘊含的知識來“消除冗余計算”和“避免不必要計算”,所以你也可以說并査集的使用是關乎本質的,只不過,知道了為什么需要引入并査集,就會強烈地感覺到一切是順理成章的了),那這個出了名的繞人的算法也就不那么難以理解和記憶了。譬如你知道排序的本質,就能夠對什么是最優排序,為什么它是最優排序有深刻的認識。四兩撥千斤。

??????

  • 包含了多得多的知識記一個算法,就只有一個算法。一個蘿卜一個坑。就好比背99乘法表只能解決乘法問題一樣。而記背后的思想,卻有助于解決一類問題。思想所處的抽象層面往往比到處都是實現細節的算法本身要低,越是低的抽象層次,越是本質,涵蓋范圍越是廣泛。數學的發展本身就體現了這個過程,抽象代數就是非常好的例子。算法誕生過程中的思路往往包含了比實際算法更本質得多的知識,實際算法乃至算法的某個特定語言的實現包含了太多表面的不相干知識,它們會阻礙對本質的理解。
  • 重在分析推理,而不是聯想:學了一大通算法和數據結構之后的一個副作用就是,看到一個問題之后,腦袋里立即不管三七二十一冒出一堆可能相干的數據結構和算法來。聯想是強大的思維捷徑,在任何時候都會搶占大腦的工作記憶,由不得你控制——比如我問你“如何尋找區間的最大值”,首先進入你的意識的肯定就是學過的那個算法,甚至算法的實現細節都一一跳了出來,也許最先跳出來的還是算法實現中某個最容易弄錯的邊界細節,或是某個比較tricky的實現技巧!然而這些其實根本不反映一個算法的本質,結果想來想去總是停留在問題的表層。而另一方面,重在思維的傳授則可以讓人養成從問題本質入手,逐步分析推理的習慣,而不是直接生搬硬套。當然,聯想本身也是極其重要的思維方法,甚至可以說是人類思維的“唯一”的特征。很多時候我們并不知道問題的本質是什么,需要靠聯想來領路。只不過,養成從問題的本質入手的好習慣絕對是有更大的好處的。

那到底什么樣的才算是授人以漁的呢?波利亞的《如何解題》絕對算是一本,他的《數學的發現》也值得一看。具體到算法書,那就不是光看text book就足夠的了,為了深入理解一個算法的來龍去脈前因后果,從一個算法中領悟盡量深刻的東西,則需要做到三件事情:

  • 尋找該算法的原始出處:TAOCP雖然本身在算法思維的傳授方面做得不好,但作為一個資料庫是絕對優秀的,基礎的算法只要你能想到的,幾乎都可以在上面找到原始出處。查到原始出處之后(譬如一篇paper),就可以去網上搜來看了。
  • 原始的出處其實也未必就推心置腹地和你講得那么到位,前面說過,算法設計出來了之后人們幾乎是不會去回顧整個的思維過程細節的,只把直指目標的那些東西寫出來。結果就又是一篇歐幾里德式的文章了。于是你就迷失在一大堆“定義”、“引理”、“定理”之中了。這種文章看上去整個寫得井井有條,其實是把發明的過程整個給顛倒過來了,我一直就想,如果作者們能夠將整個的思路過程寫出來,哪怕文字多上十倍,我也絕對會比看那一堆定義定理要容易理解得多。話說回來,怎么辦?實在找不出好的介紹,只能自己揣摩了。揣摩的重要性,是怎么說都不為過的。揣摩的一些指導性的問題有:為什么要這樣(為什么這是好的)?為什么不是那樣(有其它做法嗎?有更好的做法嗎?)?這樣做是最好的嗎?(為什么?能證明嗎?)這個做法跟其它的什么做法有本質聯系嗎?這個跟這個的區別是什么?問題的本質是什么這個做法的本質又是什么?到底本質上是什么東西導致了這個做法如此..?與這個問題類似的還有其它問題嗎?(同樣或類似的做法也適用嗎?)等等。
  • 不僅學習別人的思路,整理自己的思路也是極其重要的。詳見《跟波利亞學解題》的“4. 一個好習慣”和“7. 總結的意義”。

前一段時間我們討論組上有不少例子,見這里,或這里。

來自:http://blog.csdn.net/pongba/archive/2008/07/07/2622713.aspx

評論

#raof01?發表于2008-07-08 09:29:02??IP: 210.5.29.*
每個人都有自己的思維方式,因此不會有人傳授思維過程給別人——相當于把自己的想法強加于人,這是違背人性的。
因此,告訴你一個結果,你自己去思考。

初學一門東西,首先是記憶,然后才是思考。有了大量的基礎,才能夠全面的思考。

可以想象,當作者告訴你如何思考時,你又會想:能不能說出為什么會這樣思考呢?

#pongba?發表于2008-07-08 11:06:56??IP: 222.94.208.*
@raof01:

如果這都算強加思想違背人性的話,那么我建議兩本書:《影響力》、《態度改變與社會影響》。

此外,知識當時是問題解決的基石之一。但是一些思考法則卻是領域(知識)無關的,對所有問題解決都通用的。歐幾里德如果去做其它學問,同樣也是牛逼。知識只是料,思維才是廚師。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/452460.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/452460.shtml
英文地址,請注明出處:http://en.pswp.cn/news/452460.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Win10安全特性之執行流保護

騰訊電腦管家 2015/02/04 15:070x00 背景微軟在2015年1月22日公布了windows10技術預覽版,Build號:9926。電腦管家反病毒實驗室第一時間對其引入的新安全特性進行了深入分析。眾所周知,漏洞利用過程中攻擊者若要執行惡意代碼,需要…

【Java】 大話數據結構(1) 線性表之順序存儲結構

本文根據《大話數據結構》一書,實現了Java版的順序存儲結構。 順序存儲結構指的是用一段地址連續的存儲單元一次存儲線性表的數據元素,一般用一維數組來實現。 書中的線性表抽象數據類型定義如下(第45頁): 實現程序&am…

程序復雜程度的定量度量

對程序復雜程度進行度量的目的 1.把程序的復雜程度乘以適當常數即可估算出軟件中錯誤的數量以及軟件開發需要用的工作量, 2.定量度量的結果可以用來比較兩個不同的設計或兩個不同算法的優劣; 3.程序的定量的復雜程度可以作為模塊規模的精確限度。 …

Readhat中升級openssh

1.掛載yum源(鏡像) 如何掛載yum源(鏡像),在本人的另外一篇博客中,請戳這里 2.安裝升級所需依賴 由于升級ssh需要安裝依賴,這里提前將所需依賴安裝 指令: yum install -y zlib-dev…

android暫停活動,如何將Android暫停活動帶到前面

我有一個活動啟動異步任務,偵聽來自服務器的消息.當用戶點擊主頁按鈕時,活動暫停,異步任務繼續在后臺運行.當某個消息到達時,我希望活動恢復并在不重新創建的情況下到達前面.我嘗試了以下內容.機器人:launchMode "singleTop"intent new Intent(getBaseContext(), M…

軟件開發人員怎樣走好從技術到管理之路?

軟件開發人員怎樣走好從技術到管理之路?這是一部分技術人員思考和談論的老話題。雖然我自己并沒有豐富的管理經驗,但還是想記載下這一段時間里對這一問題的想法。從我個人走過的路來看,要走順這條路,應該做好三個方面:…

如何選擇程序設計語言

程序設計語言是人和計算機通信的最基本的工具,會影響人的思維和解題方式,影響人和計算機通信的方式和質量,影響其他人閱讀和理解程序的難易程度。 選擇適宜的程序設計語言的原因: 1.根據設計去完成編碼時,困難最少&am…

zabbix4

1.宏(Macros) 宏可以理解為一個用于文本替換模式的預設文本內容; 宏根據一系列預定義的規則替換一定格式的文本模式,一般情況下,解釋器或編譯器在遇到宏時會自動進行文本模式替換; 類似的,Zabbix可以基于宏保存預設文件…

結對項目——Subway

博客鏈接:結對項目-Subway 轉載于:https://www.cnblogs.com/Dominic-Abraham/p/9117266.html

Readhat中作安全基線

文章目錄1.新建文件夾并上傳腳本2.修改腳本中設置root2用戶的密碼字段3.添加腳本的可執行權限4.執行腳本5.嘗試使用root2登錄驗證1.新建文件夾并上傳腳本 在根目錄下的/openssh8(沒有則新建)中上傳腳本: 2.修改腳本中設置root2用戶的密碼字…

軟件測試的準則

1.所有測試都應該能追溯到用戶需求;2.應該遠在測試開始之前就制定出測試計劃;3.把Pareto原理應用到軟件測試中;4.應該從“小規模”測試開始,并逐步進行“大規模”測試;5.窮舉測試是不可能的;6.為了達到最佳…

在線計算機計器,計算機存儲單位換算-電腦容量在線換算器

APP說明存儲單位是一種計量單位。指在某一領域以一個特定量,或標準做為一個記錄(計數)點。再以此點的某個倍數再去定義另一個點,而這個點的代名詞就是計數單位或存儲單位。二進制序列用以表示計算機、電子信息數據容量的量綱,基本單位為字節B…

WordPress插件開發-創建、停用、刪除插件

插件存放目錄 wp-content/plugins 創建一個插件 在plugins創建一個文件插件文件夾,命名最好加前綴,這個前綴可以使用你的名字或者你自己的域名,防止插件和別人重名,再創建一個PHP文件名字和你的插件名一樣。我這里創建一個名為 yg…

在eclipse中使用hadoop插件

我的配置環境看我的上篇博文。 配置過程: (1)把插件放到eclipse/plugins目錄下。(我的版本上一篇也有) (3)重啟eclipse,配置Hadoop installation directory 如果插件安裝成功&#…

從程序員到技術領導者

入行 你為什么要當程序員?每當我問起很多人入行的人,回答各不相同。 有很多人是因為喜歡。誰說過:熱愛是最好的老師。當然,關鍵是熱愛是否能支撐自己把愛好做成一份職業。但不論做多久,因為熱愛或曾經熱愛&#xff0…

黑盒測試和白盒測試

黑盒測試(又稱功能測試)把程序看作一個黑盒子,完全不考慮程序的內部結構和處理過程。黑盒測試是在程序接口進行的測試,只檢查程序功能是否能按照規格說明書的規定正常使用,程序是否能適當地接收輸入數據并產生正確的輸…

Diango博客--11.Nginx + Gunicorn + Supervisor 方式部署

文章目錄0.部署前準備1.創建一個超級用戶2.更新 SQLite33.安裝 Python3 、pip3.6以及 Pipenv4.部署代碼5.使用 Gunicorn6.啟動 Nginx 服務器7.配置 Nginx8.關閉 DEBUG 模式,收集靜態文件9.使用 Supervisor管理 Gunicorn 進程10.使用 CDN 加快 Bootstrap 和 jQuery 的…

計算機更改了用戶名數據恢復,怎么把電腦更換用戶后恢復到原來的用戶呢?

如何讓administrator帳戶出現在登陸畫面?安裝Windows XP時,如果設置了一個管理員賬戶,那么系統內置沒有密碼保護的Administrator管理員賬戶是不會出現在用戶登錄列表中的。雖然它身在幕后,可卻擁有系統最高權限,為了方…

StringBuilder類

1.1 StringBuilder類概述StringBuilder:是一個可變的字符串。字符串緩沖區類。 String和StringBuilder的區別:String的內容是固定的StringBuilder的內容是可變的1.1.1 拼接字符串耗費內存原因:每次拼接都會產生新的字符串對象,而利用StringBuilder來拼接字符串自始至…

如何使用搜索技巧來成為一名高效的程序員

沒有人是完全獨立的孤島,每個人都是整體的一部分。—— 約翰多恩對于缺乏編程知識的人來說,完全有可能編寫一個網頁或小程序。如果在用Google搜索相關示例時幸運的話,可以搜到現成的代碼。即使是經驗豐富的程序員,通常也會為了節省…