數據結構與算法分析之 表(鏈表)

引言

數組是我們在編程時經常用到的一個東西,但是數組在使用中有一個很大的問題,那就是數組的容量是一開始就確定好了的,如果在使用中我們發現數組的容量不夠用,我們的編程就會有很大阻礙,於是我們就引入了表的概念。

一、表

我們在學習編程語言是肯定學過數組,那麼我們就以數組爲原型來在大腦中建立表的模型。

首先有一個數組,如
A0A1A2A3A4A4A5......AN2AN1A_0,A_1,A_2,A_3,A_4,A_4,A_5......A_{N-2},A_{N-1}
現在我們將其稱之爲,假設表就是這個樣子。這時,我們說這個表的大小是N。那麼當N等於0時我們將這個表稱之爲空表

對於非空表(即N大於零),我們說AiA_i後繼Ai1A_{i-1},同時也稱Ai1A_{i-1}前驅AiA_i。表的一個元素爲A0A_0,所以A0A_0沒有定義前驅;同樣的,表的最後有個元素AN1A_{N-1}也沒有後繼。

二、表的簡單數組實現

前面我們用一個數組的原型來在我們大腦中建立了一個表的模型,現在我們通過數組來實現一下這個表的模型。

在表的使用中,它的一些增、刪、查、改都可以用數組來完成,所以我們就直接聊最重要的那部分,也就是數組無法完成的擴容的問題,這個時候表達的概念就被引入進來了:

int[] arr = new int[10];
...
//下面我們決定需要擴大arr
int[] newArr = new int[arr.length * 2];
for(int i = 0; i < arr.length; i++)
	newArr[i] = arr[i];
arr = newArr;

這時有人就會說了,這不還是數組嗎?

對。數組只是表的一種恰當的實現,表的引入只是在數組的基礎上引入了前驅、後繼還有上面這種一個數組替換另一個數組在達到擴容的效果,表本質上的一些東西還是和數組很像。
但是,這時候就有個但是了,因爲數組的侷限性,我們添加了一些概念使數組變成表就多了自動擴容的功能。但是這些還不夠,表的使用依舊不夠快捷、高效、簡單,於是我們對錶再添加一些定義,使之變成了鏈表,經過一代又一代的優化升級,鏈表就不那麼像數組,那下面我們來講一講鏈表。

三、簡單鏈表

首先我們來畫一個鏈表的模型:

一個鏈表
鏈表由一系列節點組成,這些節點不必在內存中相連。每一個節點均含有表元素和到包含該元素後繼元的節點的鏈(link)。我們稱之爲next鏈。最後一個單元的next鏈引用null。

這時我們來比較一下數組和鏈表的優缺點:

①刪除:
在數組中,我們要刪除某個元素時,例如:1,2,3,4,5     當我們要刪除“3”時,我們要把“4”、“5”都往前移一個位置,然後把原來的“5”的位置上的數刪掉,當這個數組很大時,這個操作的時間複雜度就會很高

那當我們用鏈表時呢,我們來畫一個示意圖:
在這裏插入圖片描述
例如我們要刪除A2A_2,我們只要把A1A_1的next鏈指向A3A_3就行了,非常的簡單快速。

②添加
同樣的一個數組:1,2,3,4,5     當我們要在“2”和“3”之間添加一個元素“8”,我們需要把原來“3”的位置的數變成“8”,原來“4”的位置的數變成“3”,原來“5”的位置的數變成“4”,最後面再加一個“5”,這都打字打得手累了,非常的麻煩。

而當我們用鏈表時呢:
在這裏插入圖片描述
例如上圖將A8A1A2A_8加到A_1和A_2之間,只需要將A1A_1的next鏈指向A8A_8,再將A8A_8的next鏈指向A2A_2就完成了。

當然,也不是數組說數組全都是確定,比如在數組中查詢某個位置的元素非常簡單快捷,直接就能查到,但是鏈表因爲沒有了標號,就沒法直接查某個位置的元素了。

當然這種單向的鏈表只能從前往後查,沒有辦法從後往前查,因爲後面的元素沒有告訴前面的的元素是什麼,於是我們將單向鏈表又進行升級,就有了雙鏈表,下面是雙鏈表的模型:
在這裏插入圖片描述
我們發現,雙鏈表在單鏈表的基礎上,每個節點加了一個prev鏈,這個prev鏈指向這個元素的上一個元素的位置,這樣我們就能在任意元素上去找它的上一個元素和下一個元素了。

對於雙鏈表的一些運用,我在Java基礎的容器和各個接口部分有講到,大家可以去看一下:
Java基礎之 容器、泛型、Collection接口
Java基礎之 List接口
Java基礎之 Map接口
當然,在數據結構與算法分析這個系列裏面應該也會講。

感謝閱讀

這是本人在看《數據結構與算法分析》一書時自己的理解與總結,若對你有幫助希望能點贊收藏,有錯誤希望也各位能指出,一起學習,一起進步!

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