標籤:

如何學習數據結構?

本人學的是電子系,想考計算機的研究生,本科階段接觸的編程不算豐富,頂多是單片機的程序寫的還算多!最近在學數據結構!感覺像c啊,數據結構啊很難學習到的本質!就是頂多膚淺的了解了下它的表面原理!你說要叫我寫出二叉樹的非遞歸遍歷,二叉樹的線索化,哈夫曼編碼的實現,估計都得好睏難!請問該如何在考研中複習好數據結構!特別是跨考生呢?是不是選用的教材不對!用的是嚴奶奶的教材


————————————————2015最後更新————————————————

---------------------------------新書新方法(兼容之前的答案)---------------------------------

這是我第4次更新這個答案了。我覺得是最終版本了。因為被我忽悠的師弟師妹都學了下去。看來這個辦法真的有效果。再次強調,只是入門。


1. "我想學好基礎的數據結構和演算法! "
不多說,有這心就往下看。

2. "我應該準備些什麼? "
a. 這本橙書: 《演算法 第四版》
--亞馬遜中文版: amazon.cn 的頁面
--線上資源: Algorithms, 4th Edition by Robert Sedgewick and Kevin Wayne
b. 註冊Coursera, 依次加入這2門課: &<演算法, 第一部分&> &<演算法, 第二部分&>
Part 1: https://www.coursera.org/course/algs4partI
Part 2: https://class.coursera.org/algs4partII-006
如果沒開課, 就先標記, 這樣開課時會通過郵箱提示你.

3. "我應該做些什麼? "
先熟讀書內1.1和1.2, 最好把課後習題都做一做. 網站上開課後(即使已經開課幾周了, 沒關係), 跟住上課內容: 課本知識 + 視頻內容 + 課件重點+ Exercises (獨立完成且滿分) + Programming Assignments (獨立完成且盡量滿分) + Job Interview Questions. 從Part 1到Part 2, 跟住, 跟住, 跟住!


關於做書後練習題,參見:
演算法 第四版(algorithms 4th edition ) 這本書有配套的習題答案嗎? - 孟祥豐的回答

4. "我學完了呢!"
再去跟隔壁斯坦福的演算法公開課, 他還給證書! 因為參考書籍基本上就是是《CLRS》, 所以也就是強迫自己去仔細研讀演算法導論.
---課程名稱:
&<演算法設計與分析, 第一部分&>
&<演算法設計與分析, 第二部分&>
---課程地址
Part 1: https://www.coursera.org/course/algo
Part 2: https://www.coursera.org/course/algo2

5. "又學完啦! "
可能今後在這個方面不需要看網路上不知名人士(沒錯, 就是我)的建議了. 拜拜.

PS: 就這些?? 對, 就這些.

———————————————2015-6-9 補充———————————————
Coursera上6月19號開普林斯頓講的演算法課程了:
Coursera - Free Online Courses From Top Universities
教材就是橙寶書:
Algorithms, 4th Edition by Robert Sedgewick and Kevin Wayne

課程負擔並不大。剛入門的同學可以跟一跟。當然學習演算法還是要多做題。^_^

—————————————————原答案—————————————————
我要好好回答一下這個問題。

從剛上大學在課堂上聽老師講解,到後來自學,反覆學等種種失敗經歷給了我當頭棒喝。我這樣的小渣渣還真是難以捧本書看一看就能學懂。還真得特殊準備一套方法來學習它。藉助知乎,網上大神,ACMer的經驗分享,我自己總結了一個入門的學習方法,讓我快樂且熱情的堅持下來了對數據結構與演算法的學習。(僅針對初學者的入門級學習,大神們請繞過,拜拜么么噠

好,剩下來像我一樣的阿渣們,讓我們先來痛快的分(tu)析(cao)下為啥這東西難學:
1. 抽象,數學知識多,大多數書籍有很多數學證明,很枯燥,愛掉頭髮。
2. 反饋差。比如學完了「快速排序」也就學完了,沒什麼事做,也沒覺得自己厲害多少。但是要是學習下cocos2d-x,過幾天自己都能寫小遊戲了。學了難以分分鐘高能還真就難以堅持了。沒錯,學習這事我就是這麼投機這麼功利。
3. 孤立的知識點都很難有什麼作為,只有理解+融匯+貫通才能顯威力。
4. 沒有好「老師」。搜索下「如何學習雅思托福」,各種高能大法學習小組培訓機構怒刷一臉屏。

好了,吐槽完畢,以下是乾貨:

1.先來本入門級的好書

我把裡面的代碼全打了一遍,整不懂就一點點在草紙上演示,還整不懂的就死記硬背了下來,說不定哪天就想通了。學起來很慢,但是效果不錯。誰讓我笨呢。(現在沒事抽風還要默寫一下AVL樹的c實現,也是病沒好)2. 可視化
剛開始我就按照1這麼學,學一周就學不動了,太高估自己的能力,又冒充不下去學霸了。這知識尼瑪這麼抽象。之後發現了一個可視化工具(很多大神都推薦過啦)

http://visualgo.net

什麼冒泡插入快速排序一演示,小動畫一播放分分鐘我就都整明白了,一低頭那些小代碼也就都被我看穿看穿了。來一把倚天劍屠龍刀我也能混個山大王。

(圖是二叉堆的演示)
一可視化之後你會發現很多抽象的數據結構在腦海中有了樣子。我也說不太明白那種感覺,就好像你在一個姑娘/小夥子身上看到了愛情的樣子。

3.編程實踐
其實學習演算法可以分3個部分,演算法設計,演算法分析,演算法實踐。我個人覺得更需要靜下心花大塊時間琢磨的是前兩方面,但是演算法實踐更容易讓大家產生「我確實進步了」的正反饋。如果你參考的是我的舊答案,也就是起手看的是《數據結構與演算法分析 in C》。那麼我建議用這兩本書《C語言程序設計》和《C和指針》再去複習下C語言,之後去LeetCode上找相關題用C/C++去做。或者轉頭去看《演算法第四版》,然後去獨立完成上文提到的公開課的編程作業和書後習題。(受限於當時所學,這部分於16年刪掉重寫)

好了,總結起來就是對於每一個知識點,我們用學理論可視化編程實踐相結合的方式一個知識點一步地踏實前進但是到這裡我們真的就只是入門。所以我在這之後就愉快的重新認真地擼《演算法導論》去了。可以參見我另外一個回答:你是如何堅持讀完《演算法導論》這本書的? - 孟祥豐的回答。擼完如果覺得不夠可以繼續擼其它一些演算法書籍,詳情參見大神文章:我的演算法學習之路

雖然我還是覺得自己很渣很菜,但想想沒有昨天那麼渣了,就會很開心。


推薦神器,我已經幫助不下5個文科生轉行CS學數據結構了,絕對的深入淺出,誰用誰知道:

VisuAlgo - visualising data structures and algorithms through animation


分享一下我個人的學習方法,我覺得算是比較簡單的一套方法,對智商要求不高。


——資料來源:
(星星代表我的使用頻率)

1.教材:
數據結構與演算法分析 (豆瓣)
(經典之作,廣為人知)
數據結構 (豆瓣)
(嚴蔚敏的,就是國內大學常用的那本。嚴謹,偽代碼不錯。)
大話數據結構 (豆瓣)
(語言比較通俗。比第一本簡單易懂。btw,作者程傑老師在知乎上也相當活躍)
演算法(第4版) (豆瓣)
(圖超多。比第一本簡單易懂。)

2.慕課:
浙江大學的:數據結構 - 網易雲課堂
(真的很棒。借雷軍的一句廣告:我所有的嚮往。對於每個知識點的視頻講解,基本都涉及了:動畫演示、寫代碼的思路、寫代碼的技巧、演算法優化、演算法複雜度分析等等)
清華大學的:數據結構-學堂在線慕課(MOOC)平台
(同樣地非常非常非常好。比起浙大的數據結構,難度更深,內容更多。而且聽完課以後,不僅知其然,也知其所以然。)

3.整個互聯網!

——說明

1.教材這麼多本一起用!是的,一起用!對於某個知識點,多翻幾本書看看,哪本書講得好就看哪本。關於這些教材的優缺點,大家都應該很熟悉了。可能有人對嚴蔚敏的《數據結構》有疑慮,我個人認為這本書的優點是很嚴謹,而且代碼也不錯,就是書寫得不友好,許多地方沒有照顧讀者智商(特別是我的智商)。所以,看得懂就好,看不懂就算了,教材反正還有嘛~

2.只靠書還是不夠的,你需要搜索!比如KMP演算法,特別難理解,但是你一搜索,可以發現很多人 在博客上分享他們的理解,講解詳盡,例子豐富,比書上好多了。

3.強烈推薦慕課。這兩門慕課的老師的講解都特別棒。首先是易於理解。對於演算法概念上的分析講授,由於是視頻,在演示上比書本有先天優勢,使得內容很好理解。接著是,視頻能夠比書本帶來更大的信息量,提高了效率。最後是,看視頻很明顯比看書輕鬆有趣。

4.最後提醒,需要練習做題。只是看一遍書和視頻,那是遠遠不夠的。本人的題主要來自老師,如果你找不到題,請參考其它答主的回答,或者在我所說的那門慕課里找到做習題的網站。(不得不說,這個做題的網站也很棒。哎呀浙大好棒呀)最後,看完書和視頻能懂,只算70%;能寫代碼能跑,才能算90%

5.推薦兩個學習小技巧:(1).各個演算法都有一些隨著過程不斷地改變的數組吧?把他們在紙上推導一遍(2).嘗試一下手寫代碼(用word也行)(當然啦,不要求完全正確)。如果這樣都能寫出來,那肯定掌握了95%+。


*********補充一點兒感悟***********

按知識點來,一個一個知識點去攻破。
不必按部就班地,把某本書從第一章看到第十章,或者把某門課從從頭到尾都看。不必這樣。

對,按照知識點,一個一個來。
1.先知道是怎麼回事。
2.然後使勁理解。
3.接著做題檢驗自己。
4.下一個知識點。

以知識點為目標,而不是以某本書或某門課為目標。
至於這個知識點怎麼掌握,可以看書,可以看視頻,可以看百科,可以搜高手的教學貼等等。


不僅僅是在這個問答裡面,在別的很多地方相關的提問,很多答主都直接拋個書名。
要我說,一個書名是不夠的,得列個書單才行,不僅如此,還有視頻單,百科單,甚至僅就一個KMP演算法就可以列個分析貼單了233333.....


最近想了一下,沒有講詳細一點的學習方法。從第26,作第一次更新。

學習方法:我認為任何數據結構都可以從線性表演進而來。以順序表為例,最簡單的順序表是無序的,那麼增加一個要求,使其是有序的,那麼只需要改動一下插入操作。

依理類推,堆棧和隊列,只需要改動插入和刪除操作,即可。你看科研論文或實際項目,也是有一個較簡單的數據結構,演變而來。

串:在線性表的基礎上,增加了子串的操作,變動大一些,有回溯過程。

數組,結構稍有變動,操作也是增加得多一些,例如:迴文。

樹:結構改得較大,有分支了。性質也多一些。最基本的操作方法,是查詢。

圖:當然最複雜。各種需求。

因此:

線性表----&>樹----&>圖。這是一種演進路徑。

線性表---&>堆棧、隊列、串---&>數組---&>各種線性表;

二叉樹---&>各種二叉樹----&>B樹、B+樹----&>紅黑樹;

.....

混合使用。

依理類推。線性表是最簡單的,從線性表可以逐漸演進出其它的數據結構。

每個大類結構,都可以從基本的結構逐漸增加要求,從而演進出其它的結構來。

--------------------------------------------------------------------------------------------------------------------

不邀自來。
這個問題提得很好,好就好在「本質」兩個字。
數據結構的本質就在於:如何將現實世界中各種各樣的數據放入到內存中,並且如何在內存中操作這些數據,如何評價這些存儲方案和操作方法。
數據結構難學嗎?是難學。
為什麼難學?一開始上來就講空間複雜度、時間複雜度,就講抽象數據,當然難學了。

1、生活、生產等現實世界的數據有各種各樣的組成形式。例如一個課程的所有學生的成績(一組數據),一個班全部學生的所有課程的成績(一張表)、一個單位的人員結構(樹)等等。

2、這些數據都要先載入到內存中,再送到CPU中進行計算。

3、內存的最基本單位叫做存儲單元,一個位元組(不討論理論中的、個別情況的)。存儲單元相當於一個空盒子,可以放置數據。為了便於管理,盒子會給一個編號,當然存儲單元也會有編號,其實就是地址。理論上地址的方案可以有多種(計算機組成原理和操作系統的任務),不過對於程序員來說,這些都跟我們無關,為了簡單起見,我們把存儲單元的編號(地址)都編成0、1、2、3、4,......這樣的,於是這些編號或地址的取值範圍,我們就稱地址空間。這個地址空間,跟一維坐標軸一樣,所以是一維線性空間

4、很明顯,數據就是一個個放入到這些存儲單元中,就象我們把一個單位的物品放入盒子一樣。現在,假設一個盒子只能裝入一個單位的物品。因而,一個存儲單元也只能放入一個單位的數據。

5、接下來,假設說,我們有很多很多的空盒子(X個)。有一天,我們要將若干單位物品(N個)放入盒子中,那麼我們可以在一個盒子放入一個單位物品。依此類推,我們可以在一個存儲單元中放置一個單位的數據。

6、再接下來,我們有兩种放置方案:一個挨一個地連續地放置物品;當然,也可以不連續地放置物品。依此類推,在內存當中放置數據,也有兩種方案,連續地放置數據,或者不連續地放置數據。為什麼會有不連續的放置方案呢?原因很簡單,一個主要的原因是,內存的空間利用率高,碎片少(操作系統的存儲管理的知識,且不用理會),刪除舊有的數據很容易(這個是數據結構的內容)。

7、現在,可以把這兩個將數據放入到存儲單元的方案叫做物理存儲。對連續物理存儲方案來說,事情比較好辦,通過編號(索引、下標)就可以找到物品,對於不連續的方案,那麼我們就要在一個物品上面標記下一個物品的位置,這個標記就是下一個物品的地址(指針)。當然,在計算機中,指針的記錄本身也要佔用內存的存儲單元,所以我們在c語言中用結構體把數據和指針組織成為一個單位。通過這個指向關係,我們可以在不連續的放置方案中依次地查找我們所需要的東西(物品或數據)。

8、接下來,就象我們經常進行從盒子當中查詢物品、取用物品或增加物品等操作一樣,我們也要進行從內存當中查詢數據、取用(刪除)數據或增加數據等操作。那麼,對於不同的物理存儲方案來說,其方法是不一樣的。這個想一想,我們如何對付真實的物品,我們就如何對付內存中的數據。這就是數據的物理存儲方案的數據操作

9、好了,搞懂這些,字元串之類的知識點就不難了。

10、記住一點,只有兩種物理存儲結構:連續的和不連續的,因為內存的存儲單元的地址(編號)是0、1、2、3......(一維地址空間、或者線性地址空間)。

11、是不是只有物理存儲結構(方案)就可以了呢?在第1條中說過,現實當中的數據是有各種各樣的結構的。而在第10條,我們強調了物理放置方案只有2種:連續的和不連續的。

12、於是就產生一個問題,如何將現實世界當中的關係各種各樣的數據放入到內存之中。

13、解決第12條中的問題,我們可以分兩步走,第1步是將現實世界的數據組織成為邏輯結構,第2步再把邏輯結構的數據映射到物理結構中

14、顯然,在第1步中,我們拋去數據的其它屬性,只留下數據的兩個屬性就可以了:一個屬性是數據的值,另一個屬性就是數據之間的關係。這兩個屬性就得到一個邏輯結構:graph(圖),這就是離散數學中的圖論。那麼,這就是科學家的事情,他們負責針對具體的問題,將現實世界的數據構造出對應的graph(圖)。

15、在第2步中,我們要做的事情,把這個graph映射到物理存儲結構中,這就是數據結構要做的事情了。顯然,我們可以用數組來存儲,也可以用鏈表來存儲,回憶一下最短路徑演算法的兩個做法。ps.,二維數組、三維數組也是一個連續存儲的結構,在c語言debug下,看看地址就知道了。那麼,不連續的存儲結構,也就是鏈表,當然有很多的衍生:雙向鏈表、十字鏈表、等等。

16、顯然,不管現實世界中的數據之間的關係如何,我們都可以用graph來描述,只不過是,不同的數據關係有不同的結構而已,比如:樹、森林、mesh,等等。

17、當然,我們要掌握一些常見的graph的操作方法,最主要就是搜索方法。而且還要注意,這些方法是分兩個層次的,一個物理存儲結構這個層次,一個是邏輯存儲結構這個層次的。那麼現在,深度優先搜索、廣度優先搜索是哪個層次呢?

18、當然,我們還要掌握一下存儲結構的壓縮。

19、到了這個時候,我們還要問一下,各種方案的優劣性質如何,也就是空間複雜度和時間複雜度了。

20、當然,我們這個時候,還要進一步的問一問,能不能將這些邏輯結構給出一個統一的描述,那麼,就是抽象數據了。

21、當然,我們還要掌握邏輯存儲結構的各種樹的優化,特別是針對不同的應用,比如紅黑樹、B樹。

22、當然,我們最後還要學習一下外存的存儲結構。

23、當然,實驗是少不了的。自己debug一下內存單元的地址,並且在紙上手工的畫一下是最好了。

24、最後,有了這些基礎,剩下也就好辦了。

25、不推薦教材。尤其是國外的教材,先容許我默默地吐一下槽,各種知識點零碎不堪,不成體系,不成系統。


26、之前算是一些鋪墊。講一下數據結構的學習方法。在現實世界中,數據元素之間的關係(邏輯結構)可分為三大類:線性結構、樹結構、圖結構(有的書多了一種結構——集合,即任何數據元素之間都沒有聯繫)。線性結構是最簡單的結構。

27、把握一種數據結構,總的來說,體現在它的結構、內在性質、外在特徵、操作方法等4個方面。這4個方面是相關的。

28、線性結構,又稱線性表。其特點是:除了第一個元素和最後一個元素之外,其它一個元素都有一個前驅和後繼。線性結構的結構簡單、性質也較少、特徵也很明顯。最基本的操作方法有5種方法:初始化、獲得當前線性表的長度、插入一個元素、刪除一個元素、查詢/獲得一個元素。

29、線性表有多種類型。最簡單的線性表,是無序的。在無序的線性表的基礎上,增加一個要求,即線性表中的元素是有序的。這樣,就要求插入元素時,要對元素的值進行比較,以找到相應的插入的位置。

30、同理,可以為線性表增加其它方法,例如,逆序的操作。

31、進一步延伸,可以得到許多線性表。最經典的線性表,除了順序表、單鏈表、循環鏈表、雙向鏈表之外,還有3個最常用的線性表——堆棧、隊列、串。這3個線性表,並不難得出。

32、堆棧,是在線性表上增加了一個要求——先進後出;隊列,也是在線性表上增加一個要求——先進先出。因此,只需要改動一下插入和刪除操作,這個改動很容易。

33、串,是一種要求非常多的線性表,所以操作也非常多。有一些操作需要採用回溯演算法。

34、堆棧、隊列、串,用途廣泛。在具體的運用中,有很多變種。比如,隊列,在操作系統的進程管理的優先順序演算法中,採用了多級隊列,在進程狀態切換的演算法中,採用了多個隊列。但是,並不可怕,只要學會如何分析需求,從而改動操作方法,就可以實現。基本上,其它的操作方法都是在常規的5個方法的基礎上演變而來。


以下答案來自 Quora。
翻譯很挫,還請見諒 :)

I see it time and again in Google interviews or new-grad hires: The way data structures and algorithms—among the most important subjects in a proper computer science curriculum—are learnt is often insufficient. That"s not to say students read the wrong books (see my recommendation below) or professors teach the wrong material, but how students ultimately come to understand the subject is lacking.

我多次在google面試或者畢業招聘的時候看到這樣的情形:學習數據結構和演算法--CS課程裡面幾乎最重要的課程--的方式很不科學!!
到不是說大家用的書或者老師用的材料不對,而是說學生們對於這些課程本身的理解非常缺乏.

The key to a solid foundation in data structures and algorithms is not an exhaustive survey of every conceivable data structure and its subforms, with memorization of each"s Big-O value and amortized cost. Such knowledge is great and impressive if you"ve got it, but you will rarely need it. For better or worse, your career will likely never require you to implement a red-black tree node removal algorithm. But you ought be able—with complete ease!—to identify when a binary search tree is a useful solution to a problem, because you will often need that skill.

打好數據結構和演算法基礎的關鍵並不在於對於所有數據結構的細緻的了解,不是記住每一個大O值或者攤余成本..((@_@;)? [不懂]).
如果這些知識你都掌握了,當然很棒並且可以給人留下很深的印象,但是你基本上用不著啊!
你的職業生涯中或許永遠都不會要求你實現一個紅黑樹刪除節點的演算法.但是!你必須有能力而且手起刀落輕輕鬆鬆的識別出什麼時候使用二叉樹更簡單更有效, 因為你十分需要這樣的技巧.

So stop trying to memorize everything. Instead, start with the basics and learn to do two things:

  • Visualize the data structure. Intuitively understand what the data structurelooks like, what it feels like to use it, and how it is structured both in the abstract and physically in your computer"s memory. This is the single most important thing you can do, and it is useful from the simplest queues and stacks up through the most complicated self-balancing tree. Draw it, visualize it in your head, whatever you need to do: Understand the structure intuitively.
  • Learn when and how to use different data structures and their algorithms in your own code. This is harder as a student, as the problem assignments you"ll work through just won"t impart this knowledge. That"s fine. Realize you won"t master data structures until you are working on a real-world problem and discover that a hash is the solution to your performance woes. But even as a student you should focus on learning not the minutia details but the practicalities: When do you want a hash? When do you want a tree? When is a min-heap the right solution?

所以,不要試圖記住所有的東西.而是從基礎開始,做兩件事:

  • 第一件事. 把數據結構圖形化,視覺化.(突然想起來我高中競賽老師說的一句話:數形結合千般好,一旦不做萬事休啊! 就是要畫圖! )在直覺上感受一個數據結構是什麼樣子的.使用它是什麼感覺,抽象上和具體實現上是什麼樣子的.這就是最重要的事情.並且無論是對於簡單的隊列,棧還是天殺的平衡樹都很重要而且有效.把數據結構畫出來,在你的腦袋瓜裡面就能想像出來,總之,你需要做的就是,直觀的去了解這些數據結構.
  • 第二件事.學習什麼時候用什麼樣的數據結構和演算法.對於學生來說這很難,而且你要做作業的時候老師也沒告訴你們這該怎麼辦.╮( ̄▽ ̄")╭ 不過沒關係. 你要認識到當你真正處理到現實問題的時候或許你才能掌握某些數據結構,比如哈希表.但是即使是個學生,你也應該知道數據結構的實用性:什麼時候你需要個哈希表,什麼時候你需要個樹,什麼時候你需要個堆? 而不是一開始就陷入到追求細節中去.

One of the questions I ask in Google engineering interviews has a binary search tree as a potential solution (among others). Good candidates can arrive at the binary search tree as the right path in a few minutes, and then take 10-15 minutes working through the rest of the problem and the other roadblocks I toss out. But occasionally I get a candidate who intuitively understands trees and can visualize the problem I"m presenting. They might stumble on the exact algorithmic complexity of some operation, but they can respond to roadblocks without pause because they can visualize the tree. They get it.

我在google面試的時候,我經常會問一個可以由二叉樹搜索解決的問題. 好的應聘者可以幾分鐘內就可以想到用二叉樹來解決,而且對於我的其他問題也差不多10-15分鐘就可以解決.當然,偶爾會有一個應聘者,他能直觀的認識樹這種結構,而且可以把我的問題形象化,圖形化的描述出來.當然他或許對於某些操作的時間複雜度不甚了解,但是對於問題他卻可以立馬回應,因為他們腦袋裡就有這樣的樹結構啊~所以他也能拿到工作啊.

As for a book, there is but one: Introduction to Algorithms by Cormen, Leiserson, Rivest, and Stein, otherwise known as CLRS.

至於書嘛,只推薦一本--- &<演算法導論&>

If you want another text, perhaps one with more examples in a specific language, I recommend Robert Sedgewick"s Algorithms in C++ orAlgorithms in Java, as appropriate. I prefer CLRS as a text, but you might find these a better teaching aid.

如果你想要一本有很多例子並且和語言相關的書的哈u,我就推薦 &&<Algorithms in Java&> 當然我還是更推薦&<演算法導論&>,不過這些也是很好的教輔書啦~


方法只有一個:敲代碼。把《數據結構》里的代碼全部實現一遍,把配套的習題集都做一遍,沒有學不好的數據結構!!!

(圖片可放大...)

附上學習數據結構的博客,已經更新完成:

《數據結構-C語言版》(嚴蔚敏,吳偉民版)課本源碼+習題集解析使用說明

------------------------------------------更新----------------------------------------
我要鄭重地替這本書辯解:
1.這本書的代碼並不是直接可以執行的C代碼或者C++代碼,而是偽代碼,所以你如果照著敲了一遍運行不了,是非常正常的事。
2.打開前言的第1頁第三段,可以看到作者說:「全書採用類C語言...盡量考慮C語言的特色」,"本書並未直接採用類和對象等措施,而是從C語言中精選了一個核心子集,並增加C++語言的引用調用參數傳遞方式等,構成了一個類C描述語言",由此可見,本書中的代碼是雜糅了C語言和C++的語法,但以C語言為主的。
3.如何正確運行本書中的程序呢?我的建議是先確定自己擅長使用C語言?還是C++語言?或者是其他種類的語言,然後在看懂演算法思路的基礎上,使用自己擅長的語言,試著去實現演算法過程,而不是生搬硬套。最常見的問題是很多人學了點C又學了點C++,但是又不能正確區分這兩種語言,導致寫出來的東西一會兒正常,一會兒不正常,檢查錯誤又檢查不到,最後學著學著放棄了。
4.書中的個別程序思路並不適合組合在一個完整的工程中,但其演算法都是正確的,這一點我驗證過,所以,馬列主義要活學活用,要根據自己的理解,做適當的變通,只要思路正確、結果正確就行,形式不重要。

------------------------------------------再更新----------------------------------------

目前全書的源碼以及配套習題冊的解答已更新完畢,個別證明題目留坑待填,或者有看到的網友會解答的話可以交流一下...


看了這麼多答案,感覺很多人都沒回答到點子上。

今天剛好幫表弟解釋這個問題。我來講下我的學習體驗。

其實學習數據結構重點並不在於哪本書,哪個教程,那個網課。

首要的問題是,要搞清楚數據結構的目的。

故名思議,數據結構這門學科就是為了讓計算機能夠以更加高效,簡單,便捷的方式來存儲和使用數據而產生的。所有的目標都圍繞著存和取兩個目標打轉。在這兩個目標下,有幾個評估的指標,存取效率,可擴展性,順序性,可排序性這幾個特徵。

要明白這幾種特徵,就需要先搞清楚幾個前提,

一、內存的數據存儲模式,是以順序排列的方式存儲的。

也就是說,內存中的數據是起點是0,終點根據內存的大小和操作系統而定的一個順序的序列。0被佔用,後面存入的數據則依次存入。

二、程序在一個線程中,只能同時從一個地址來取數據。所以,除了圖之外,所有的數據結構都有且只有唯一的取數入口。所以,必須從一個入口來進行取數。

三、內存的數據存取並不是只有一個線程,是很多歌程序不斷的進行操作的。所以數據的分布是不連續的,並不一定可以一次性找到足夠大的一塊內存來存放一次操作所需要的所有數據。

可以用磁碟碎片整理的圖示來類比一下,使用一段時間以後,內存中的數據大概就是這個樣子的,此時要想一次性開出一大塊數據,是不可能的,所以要想辦法解決數據量無限增加時的數據分配。

四、數據結構的基礎是最吃理解的一門課程,只要理解了,除了遍歷演算法之外,都豁然開朗,所以刷題毫無意義。關鍵是理解集中數據結構存在的目的,和之間的區別。


數據結構分為三大類。

一、線性表:

這個是為了解決單線存儲而出現的,數組就是最簡單粗暴的存儲方法。就是直接拉出一大塊數據存在那裡。數組的快速存取其實只是一個副作用,因為所有的數據都在一起,可以直接算出來數據的地址。鏈表則是為了解決可以無線增長的需求的。因為找不到一大塊可以連續的存入數據,甚至也不知道程序可能使用的數據總量,所以就沒辦法劃分一塊數據來使用,劃小了不夠用,劃大了浪費(這在早年是非常大的事情)。所以必須想辦法解決問題。最後採用的方法就是從入口開始,每一個數據塊不僅僅有數據,還會有指向下一個數據塊的線索,用來尋找下一個數據。這就是鏈表。所謂的雙向鏈表,只是加了一個向前的線索的鏈表而已。隊列,棧,都是線性表的特殊形態。進行了操作上的限制罷了。沒有什麼太複雜的。

二、樹:

樹是為了解決單一入口下的非線性關聯性的數據存儲或者排序這樣的功能而來的。

最常見的應用是編程時候的map,就是利用了二叉樹的可排序和可以快速插入並且保持序列完整的特性來構建鍵值數據對,來實現數據的插入增加以及快速查找的能力的。

還有做語法解析,文字處理等等很多場景也會用到樹。這就不一一贅述了。當然在吃透線性表的基礎上,再去理解樹也並不難。因為樹相對於鏈表,就是每個節點不止有一個後續節點但是只有一個前置節點。

三 圖:

圖是數據結構里最難的一部分,但是很多學校並不作為重點,因為確實大部分人不會用到。

圖其實就是把線性表進一步擴展,每個節點會有不止一個前置和後綴節點,而且前置和後綴的概念也不再明晰,變成了關聯節點而已。

具體的應用主要是一些特殊的演算法和圖形學上的一些使用。我自己也沒有用過。沒辦法細講了。


總之數據結構的前期學習要重理解。以倒推的方式,搞清楚每種數據結構產生的目標。多畫畫圖,思考一下,理解透徹以後。再去做練習題會事半功倍。


補充下目前點贊最多的答案,中文版VisuAlgo網站為VisuAlgo - 數據結構和演算法動態可視化 (Chinese)


把書上的例子都自己手動寫一遍編譯一次,比你光看書強一百倍。
相比較於看書上的例子,數據結構更重要是思考和運用


分享一下我們係數據與演算法老師的建議吧,學習數據結構/演算法要經歷3個階段:

  1. 理解數據結構/演算法的原理
    也就是說能夠在腦子裡明白這個數據結構/演算法是怎樣工作的,知道這樣做的正確性。當然,如果理解有困難可以藉助其他知友們推薦的可視化工具:VisuAlgo - 數據結構和演算法動態可視化 (Chinese)
  2. 用C/C++實現
    這一步也是最考驗一個人編程基本功的。寫出簡潔、優雅、具有表現力的代碼能夠使數據結構的學習變得很簡單。反之,如果介面設計得太複雜、邊界情況不注意處理或者不注意效率的話,就會出現各種bug:內存泄漏、野指針、遞歸棧溢出……
    因此,建議學習的時候多參考優秀的教材。我用的是鄧俊輝大大的數據結構C++版(這裡安利一下學堂在線上的配套MOOC數據結構(2015秋)-學堂在線慕課(MOOC)平台)和Weiss的數據結構與演算法分析。這兩本書的主頁上都提供了源代碼下載。
  3. 分析時間和空間複雜度、優點、缺點以及適用於解決的問題

學習了一段時間數據結構以後,我發現沒有哪一個數據結構/演算法是萬能的,每個數據結構或者演算法都有自己擅長解決的問題。比如著名的快速排序演算法在對一些特殊序列排序時也會發生性能的惡化,更不必說對鏈表排序必須用到歸併排序演算法。因此,能夠分析每個數據結構/演算法的優缺點和適用範圍是很重要的。在應用場合中,也許你不需要自己造輪子,用現成的程序庫就可以了。但至少你要知道應該使用哪種輪子。

希望題主學習愉快~


我是計算機的研究生哦,考研過來的,可能能給你一點兒幫助。
首先,你的目的是考研,我們姑且不討論如何精通數據結構這個問題,我自己也好多不懂,我們目前的目的是考研的數據結構題我會。
明確了目的之後,既然題主是跨考,那麼應該基礎一般,因此很關鍵的第二步就是選好教材和輔導書,教材我當時用的是《數據結構·C++語言描述》,輔導書用的是王道的(很推薦王道論壇的計算機考研書)。
接下來第三步不要急於開始做題,先把線性表、鏈表、樹、圖、各種排序演算法,熟悉一遍,熟悉需要達到的結果是提到一種結構,腦海立馬可以反映出其中元素的組織方式,插入刪除操作的步驟。
接下來就是刷題,不要看答案,自己按自己理解的方式做,做完再看答案有錯誤仔細看解析。
如果有時間的話,可以在集成環境里實現一下這幾個簡單的結構,只實現不考慮優化等其他因素的話是很簡單的,畢竟考CS的研究生,代碼能力還是要有的。
最後,不要打算一口吃個胖子,看多難的書看多複雜的實現,多刷題才是制勝之道,祝題主考研順利~


學習數據結構與演算法的目的不同,學習的方法不同,當然,最終達到的效果與感情的差距也很明顯。
如題主所說,如果是為了考試,可以採用應試教育的學習方法,你懂的,就那些題。

但我想說的是,對於IT同學來說,學習演算法的真正意義與方法。雖然現在越來越多的工具,庫已經完全封裝了很多底層實現,讓更多的程序員是傻瓜式的使用即可,這一方面確實促進了開發效率,但這並不能代表我們不需要去了解演算法本身的作用。只有知道某一個組件真正的實現原理(很多時候就會用到演算法),才能明白其真正的應用場景,在哪種情況下合適,因為任何演算法都有優缺點,都會有一個最佳應用場景和最壞應用場景。
特別是對於後端開發,涉及到高並發,大數據處理相關的開發的人來說,演算法相當重要,特別是對於性能要求極佳的場景。如果不明白,雖然你能夠實現功能,但你永遠無法知道如何進行性能調優,無法真正將項目產品化。

如何實好演算法,其實是多看,多練,多寫,最為重要的,就是了解演算法的本質,了解的辦法無他,練習。
當然,我們可以站在別人的肩膀上。如下視頻可參照學習。數據結構與演算法視頻剖析


寫了很多,發現題主是計算機相關專業的,那就好說多了。
首先,你得把嚴奶奶書裡面的程序都自己敲一遍。如果書上代碼通過不了,那就補充相關代碼,讓其能夠展示數據結構演算法思想。
敲代碼的過程中,如果你不能理解語句的含義,那麼一定要在練習本上模擬上面的代碼操作。
數據結構多用指針,學習C語言的時候務必掌握指針的指針。
最好先別看演算法導論,如果只是為考研準備,那就仔仔細細把嚴奶奶書上的程序敲一遍,所用時間還是比較短的。
去年學的數據結構,學的不怎麼紮實,主要是到後期圖演算法那裡比較麻煩。前面的代碼我可是真的認認真真敲了個遍。

總結下來,兩點:
1、把演算法變成代碼
2、遇到不理解的演算法,在練習本上模擬其步驟,理解後再執行第1點。


理解不同的應用場景,理解針對這種場景適合採用何種數據結構,你就不會覺得數據結構沒用,反而會激發你攻克各種數據結構的決心,舉個例子,機械硬碟為什麼索引文件系統常常採用B+樹?因為機械硬碟順序讀取快、隨機讀取慢的問題,B+樹就是專門針對機械硬碟這個工作特點提出的!那麼固態硬碟應該採用什麼數據結構?
類似地,不要總折騰數據結構、發明數據結構,理解不同應用場景的特點,遠比一味地看演算法、數據結構來的實在。


去年才把自己一個代碼補充完整。就是一段對AVL樹的刪除部分完成,數據結構也是我認為的大學課程中最重要的2門之一,另外一門是操作系統。

我們這代人很衰,大學的課程裡面只有嚴蔚敏老師的《數據結構》可以看。我們當年的老師是學校內的四大名捕(考試的都知道),老師上課我重來不去,但他布置的上機作業,也就是各種數據結構實現,我全部完成了,考試老師也沒有難為我。我覺得受益匪淺。那本教材是我大學啃得最爛的書,還包了書皮,可惜在上班後丟失了。

所以把所有的(大部分)的演算法和數據結構寫一遍。這是一個做合格程序員的基礎。
絕對大有收穫。
從語言到調試,你都可以上升一個台階。
如果是C++的程序員,再把《STL源碼剖析》看看。會對設計實現有一些新的認識。

回到正題,如果兄台覺得《數據結構》沒意思,我覺得也許程序員這個職業不合適你。


其實一門知識,第一遍學完覺得不滿意是很正常的呀,複習複習會有新的收穫,不要覺得這是自己做錯了什麼,掌握一門複雜的知識就是要這麼個過程。


學習數據結構先應該理解每種數據結構的思想,然後用一種自己喜歡的語言去實現,同時可以到OJ上找相對應的題做,我想那樣對理解會更深些,掌握的會更好。


完全沒有相關基礎的話(比如鏈表寫的也不是很熟練的話)推薦《大話數據結構》入門,代碼質量一般(貌似是取自嚴蔚敏版的教材),但容易入門。

有點感覺之後(常見排序演算法以及寫個stack queue或者簡單二叉樹感覺沒有問題的時候)推薦鄧俊輝版數據結構(C++版),感覺少有的講解詳細的國內書籍,重點是不只告訴你知識點之後直接給你代碼,而是讓你順著思路逐步把其用途和利弊搞清楚。

最後《演算法導論》的數據結構部分還是比較簡單的,看了這些書之後才發現經典之作就是經典之作。

實踐方面:學數據結構免不了想造點輪子,可以參考STL的實現,拋去內存管理和迭代器的部分只看實現的話還是很容易從中學到東西的。 從vector、list到 hashtable 到紅黑樹等都有。
等你裸寫平衡樹以及圖論的幾個經典演算法之後基本上數據結構就okay了。


《大話數據結構》
你,值得擁有!


試著回答下這個問題。

首先申明下,本人演算法學渣,工作幾年面試中經常被演算法虐,但一直希望把演算法學好。以下內容建議只適合想要演算法入門的同學。

我覺得,學習演算法的途徑有以下幾個:

  1. 把所有經典演算法寫一遍。二分查找,幾種經典排序如冒泡,快排,歸併排序,並弄清楚他們的差別;top-k , 二叉樹,二叉查找樹,平衡樹,B樹系列,大/小根堆等,最好知道幾個這些演算法的應用場景,加深理解。
  2. 看演算法源碼。這一步,你可以去看一些開源系統裡面應用演算法知識的源碼,比如緩存系統裡面的雙向鏈表+hash實現;資料庫系統裡面B+樹的使用實現過程。
  3. 加入演算法學習社區,相互鼓勵學習。學習演算法是一個漫長痛苦的過程,有時候也會很寂寞,能找到志趣相投的三兩好友一起學習,能更好的幫助你堅持下去。
  4. 看經典書籍。像《編程珠璣》《數據結構與演算法分析》《演算法導論》等,當然還有很多其它好的演算法書籍。
  5. 刷題。接下來,你應該到處去刷題,找到所有你能找到的題目,試著給出答案。可以看看這幾本樹:《劍指offer》 , 《編程之美》 ,《結構之法:面試和演算法心得》,另外還有一些編程網站上也有很多題目,比如 LeetCode Online Judge , 九度Online Judge,用代碼記錄你的成長之路! 。

我自己也在github上建了個倉庫,分門別類彙集了很多題目,或許可以幫你節省些時間Learn-Algorithms/演算法問題選編 at master · nonstriater/Learn-Algorithms · GitHub


推薦閱讀:

TAG:數據結構 |