數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)心得
在2021這個寒假,由于想要把編程能力打扎實,我自學(xué)了數(shù)據(jù)結(jié)構(gòu)與算法,其實學(xué)的不夠細致,基本上只過了一遍,在代碼實戰(zhàn)方面目前只做了個鏈表和一個無向圖的深度優(yōu)先遍歷,深度優(yōu)先遍歷這個目前還做的不夠好。
在沒有學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之前,我們的專業(yè)在大一的時候開始學(xué)習(xí)了C語言,當(dāng)時的期末作業(yè)是要我們寫一個學(xué)生信息管理系統(tǒng),也就是一個存放學(xué)生結(jié)構(gòu)體的一個數(shù)據(jù)集合,然后能夠?qū)崿F(xiàn)增刪改查功能,我依稀記得當(dāng)時理解指針還是有點費力的事情,記得當(dāng)時期末作業(yè)一做做了兩天。記得做完后還挺有成就感,還錄的解說視頻還錄了足足半小時。
現(xiàn)在在學(xué)完數(shù)據(jù)結(jié)構(gòu)的時候再回看我當(dāng)時設(shè)計的C程序,感覺缺點一下子就出來了,首先代碼比較冗余,包含相同功能的代碼都明顯重復(fù)了,當(dāng)然這是我的API的設(shè)計不夠好。其次,整個學(xué)生數(shù)據(jù)集合的結(jié)構(gòu)設(shè)計的也不夠好,當(dāng)時可以說用鏈表來做,但是由于當(dāng)時指針學(xué)習(xí)的并不深入,所以就只用結(jié)構(gòu)體數(shù)組來做了。直接使用數(shù)組來作為學(xué)生數(shù)據(jù)庫的缺點很明顯了:一是容量固定,不能夠動態(tài)擴充容量,二是增加和刪除學(xué)生會比較麻煩。主要是第二點讓我看了感覺十分尷尬,因為當(dāng)時我的增添學(xué)生的做法是插空法,刪除學(xué)生的做法也就是直接刪除,數(shù)組按下標(biāo)查找快的優(yōu)勢形同虛設(shè),學(xué)完數(shù)據(jù)結(jié)構(gòu)的線性表之后我才知道原來對于靜態(tài)的數(shù)組來說,每一次增添或者刪除學(xué)生都需要重新創(chuàng)建一個新的數(shù)組,然后把以前的數(shù)組里的內(nèi)容按順序放到新數(shù)組里。同時相應(yīng)的容量數(shù)字也會發(fā)生變化。這看起來性能開銷一下子就變大了起來,于是便有了鏈表,它是由指針串起來的一個結(jié)構(gòu),由于它這靈活的特性,解決了數(shù)組增刪麻煩的問題。但是鏈表也有它的缺點,就是訪問一個元素不能夠直接通過一個下標(biāo)來訪問其元素,只能老老實實從頭順著鏈表遍歷了。
在我理解了線性表中的數(shù)組和鏈表之后,我還看到了很多其他有意思的線性表結(jié)構(gòu),有:靜態(tài)鏈表、循環(huán)鏈表,雙向鏈表,雙向循環(huán)鏈表……不同的場合有著不同的應(yīng)用。
數(shù)據(jù)結(jié)構(gòu)當(dāng)然不止有線性表的結(jié)構(gòu),還有更有意思的棧、隊列、樹、圖等結(jié)構(gòu)。
對于棧來說我感覺它應(yīng)用非常廣泛,一說到棧,第一個想到的就是“棧內(nèi)存溢出”,因為Java里就有一個內(nèi)存區(qū)域叫棧內(nèi)存,在寫遞歸調(diào)用的時候就容易出現(xiàn)這個bug。棧遵循先進后出的規(guī)則。與棧相似但又不一樣的一個結(jié)構(gòu)是隊列,它也有棧的一系列功能,但是它遵循的規(guī)則是先進先出。逆波蘭表達式就是可以用棧來實現(xiàn),它主要用于計算解析一個數(shù)學(xué)表達式,我個人猜測棧結(jié)構(gòu)會廣泛應(yīng)用在編譯器解析代碼里。隊列結(jié)構(gòu)也十分基礎(chǔ)實用,一些算法就可以基于這個結(jié)構(gòu)來實現(xiàn),比如廣度優(yōu)先算法。
接下來還學(xué)了樹結(jié)構(gòu),樹這一章里內(nèi)容很豐富,就樹的類型就有很多種,還有樹的遍歷方式,以及樹和二叉樹的轉(zhuǎn)換。
最后就是圖,學(xué)到圖的時候開始感覺難度上來了,尤其是圖的遍歷問題,以及最短路徑,拓撲排序,這些問題……