鏈表

鏈表中最簡單的一種是單向鏈表,它包含兩個域,一個信息域和一個指針域。這個鏈接指向列表中的下一個節點,而最後一個節點則指向一個空值。

Singly-linked-list.svg
一個單向鏈表包含兩個值: 當前節點的值和一個指引下一個節點的鏈接

一個單向鏈表的節點被分成兩個部分。第一個部分保存或者顯示關於節點的信息,第二個部分存儲下一個節點的地址。一個單向鏈表只向一個方向遍歷。

鏈表最基本的結構是在每個節點保存數據和到下一個節點的地址,在最後一個節點保存一個特殊的結束標記,另外在一個固定的位置保存指向第一個節點的指針,有的時候也會同時儲存指向最後一個節點的指針。一般查找一個節點的時候需要從第一個節點開始每次訪問下一個節點,一直訪問到需要的位置。但是也可以提前把一個節點的位置另外保存起來,然後直接訪問。當然如果只是訪問數據就沒必要了,不如在鏈表上儲存指向實際數據的指針。這樣一般是爲了訪問鏈表中的下一個或者前一個(需要儲存反向的指針,見下面的雙向鏈表)節點。

相對於下面的雙線鏈表,這種普通的,每個節點只有一個指針的鏈表也叫單向鏈表,或者單鏈表,通常用在每次都只會按順序遍歷這個鏈表的時候(例如圖的鄰接表,通常都是按固定順序訪問的)。

鏈表也有很多種不同的變化:

[編輯] 雙向鏈表

主條目:雙向鏈表

一種更復雜的鏈表是“雙向鏈表”或“雙面鏈表”。每個節點有兩個連接:一個指向前一個節點,(當此節點爲第一個節點時,指向空值或者空列表);而另一個指向下一個節點,(當此節點爲最後一個節點時,指向空值或者空列表)

Doubly-linked-list.svg
一個雙向鏈表有三個整數值: 數值, 向後的節點鏈接, 向前的節點鏈接

在一些低級語言中, XOR-linking 提供一種在雙向鏈表中通過用一個詞來表示兩個鏈接(前後),我們通常不提倡這種做法。

雙向鏈表也叫雙鏈表雙向鏈表中不僅有指向後一個節點的指針,還有指向前一個節點的指針。這樣可以從任何一個節點訪問前一個節點,當然也可以訪問後一個節點,以至整個鏈表。一般是在需要大批量的另外儲存數據在鏈表中的位置的時候用。雙向鏈表也可以配合下面的其他鏈表的擴展使用。

由於另外儲存了指向鏈表內容的指針,並且可能會修改相鄰的節點,有的時候第一個節點可能會被刪除或者在之前添加一個新的節點。這時候就要修改指向首個節點的指針。有一種方便的可以消除這種特殊情況的方法是在最後一個節點之後、第一個節點之前儲存一個永遠不會被刪除或者移動的虛擬節點,形成一個下面說的循環鏈表。這個虛擬節點之後的節點就是真正的第一個節點。這種情況通常可以用這個虛擬節點直接表示這個鏈表,對於把鏈表單獨的存在數組裏的情況,也可以直接用這個數組表示鏈表並用第0個或者第-1個(如果編譯器支持)節點固定的表示這個虛擬節點。

[編輯] 循環鏈表

主條目:循環鏈表

在一個 循環鏈表中, 首節點和末節點被連接在一起。這種方式在單向和雙向鏈表中皆可實現。要轉換一個循環鏈表,你開始於任意一個節點然後沿着列表的任一方向知道返回開始的節點。再來看另一種方法,循環鏈表可以被視爲“無頭無尾”。這種列表很利於節約數據存儲緩存, 假定你在一個列表中有一個對象並且希望所有其他對象迭代在一個非特殊的排列下。

指向整個列表的的指針可以被稱作存取指針。

Circularly-linked-list.svg
用單向鏈表構建的循環鏈表

循環鏈表中第一個節點之前就是最後一個節點,反之亦然。循環鏈表的無邊界使得在這樣的鏈表上設計算法會比普通鏈表更加容易。對於新加入的節點應該是在第一個節點之前還是最後一個節點之後可以根據實際要求靈活處理,區別不大(詳見下面實例代碼)。當然,如果只會在最後插入數據(或者只會在之前),處理也是很容易的。

另外有一種模擬的循環鏈表,就是在訪問到最後一個節點之後的時候,手工的跳轉到第一個節點。訪問到第一個節點之前的時候也一樣。這樣也可以實現循環鏈表的功能,在直接用循環鏈表比較麻煩或者可能會出現問題的時候可以用。

[編輯] 塊狀鏈表

塊狀鏈表本身是一個鏈表,但是鏈表儲存的並不是一般的數據,而是由這些數據組成的順序表。每一個塊狀鏈表的節點,也就是順序表,可以被叫做一個

塊狀鏈表通過使用可變的順序表的長度和特殊的插入、刪除方式,可以在達到O( /sqrt n )的複雜度。塊狀鏈表另一個特點是相對於普通鏈表來說節省內存,因爲不用保存指向每一個數據節點的指針。

[編輯] 其它擴展

根據情況,也可以自己設計鏈表的其它擴展。但是一般不會在邊上附加數據,因爲鏈表的點和邊基本上是一一對應的(除了第一個或者最後一個節點,但是也不會產生特殊情況)。不過有一個特例是如果鏈表支持在鏈表的一段中把前和後指針反向,反向標記加在邊上可能會更方便。

對於非線性的鏈表,可以參見相關的其他數據結構,例如。另外有一種基於多個線性鏈表的數據結構:跳錶,插入、刪除和查找等基本操作的速度可以達到O(nlogn),和平衡二叉樹一樣。

[編輯] 存儲結構

鏈表中的節點不需要以特定的方式存儲,但是集中存儲也是可以的,主要分下面這幾種具體的存儲方法:

共用存儲空間
鏈表的節點和其它的數據共用存儲空間,優點是可以存儲無限多的內容(不過要處理器支持這個大小,並且存儲空間足夠的情況下),不需要提前分配內存;缺點是由於內容分散,有時候可能不方便調試
獨立存儲空間
一個鏈表或者多個鏈表使用獨立的存儲空間,一般用數組或者類似結構實現,優點是可以自動獲得一個附加數據:唯一的編號,並且方便調試;缺點是不能動態的分配內存。當然,另外的在上面加一層塊狀鏈表用來分配內存也是可以的,這樣就解決了這個問題。這種方法有時候被叫做數組模擬鏈表,但是事實上只是用表示在數組中的位置的下標索引代替了指向內存地址的指針,這種下標索引其實也是邏輯上的指針,整個結構還是鏈表,並不算是被模擬的(但是可以說成是用數組實現的鏈表)。

[編輯] 鏈表的應用

主條目:鏈表的應用

鏈表用來構建許多其它數據結構,如堆棧,行列和他們的衍生。

節點的數據域也可以成爲另一個鏈表。通過這種手段,我們可以用列表來構建許多鏈性數據結構;這個實例產生於Lisp編程語言,在Lisp中鏈表是初級數據結構,並且現在成爲了常見的基礎編程模式。 有時候,鏈表用來生成聯合數組,在這種情況下我們稱之爲聯合數列。這種情況下用鏈表會優於其它數據結構,如自平對分查找樹(self-balancing binary search trees)甚至是一些小的數據集合。不管怎樣,一些時候一個鏈表在這樣一個樹中建立一個節點子集,並且以此來更有效率低轉換這個集合。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章