Java集合原始碼分析之基礎(一):陣列與連結串列

大大紙飛機發表於2018-08-07

陣列連結串列是資料結構中最基本的部分,也是其餘眾多資料結構的基礎。即使在Java中,這兩種結構使用的也很普遍。這裡我們會先對它們進行簡要分析。

陣列

在java中,陣列定義為一種基本型別,其可以通過下標獲取到對應位置的資料。那麼這種結構的資料,在記憶體中是怎麼存放的呢?

陣列的結構示意圖

正如上圖所示,陣列在記憶體中是一段連續的儲存單元,每個資料依次放在每個單元中。分析這種結構,我們可以得出以下幾個結論:

  • 建立一個陣列,必須宣告其長度,以在記憶體中尋找合適的一段連續儲存單元。這也意味著陣列的大小是固定的,我們無法動態調整其大小。

  • 想要獲取陣列中第i個元素,其時間複雜度是 O(1),因為可以根據其地址直接找到它。同理修改也是。

  • 陣列對查詢表現一般,要想查詢一個元素,需要遍歷,時間複雜度為O(n)

  • 因為地址連續,想要在陣列中插入一個元素是複雜的,因為從插入位置起,後邊的所有元素都需要向後移動一位。同理刪除也是,只是移動方向為向前。並且,當陣列存滿時,就無法繼續插入了。

  • 因為陣列要佔據一整塊記憶體,有可能產生許多的碎片,也可能因為找不到合適的記憶體塊,而導致儲存失敗。

總結起來就是:陣列大小固定,查詢迅速,增刪複雜,需要完整的記憶體塊,容易產生碎片。

連結串列

連結串列是一種離散儲存結構,其在記憶體中儲存不是連續的,每個資料元素都通過一個指標指向其下一個元素的地址。根據指標域的不同,連結串列又分為單連結串列、雙向連結串列、迴圈連結串列等,這裡我們只分析單連結串列。示意圖如下所示:

連結串列的結構示意圖

分析這種結構,我們可以得出以下幾個結論:

  • 宣告一個連結串列時,不需要知道其長度,也不需要連續的記憶體塊,所以其大小可以動態調整。

  • 連結串列的每個元素都分為資料域和指標域,前者是實際儲存的資料,後者則指向下一個元素的地址。和陣列相比,每個元素需要佔用的記憶體更大了。

  • 要獲取連結串列的第 i 個元素變得複雜,因為其地址存放在它上一個元素的指標域裡,所以只能從第一個元素起,進行 i 次操作。同理修改也是。

  • 連結串列對查詢表現也一般,需要遍歷,時間複雜度為O(n)

  • 增加與刪除一個元素更方便了,因為沒有對記憶體地址的限制,我們只需要在對應節點合理處理下指標域的值,就可以把一個元素插入連結串列或者從連結串列刪除。

  • 連結串列對記憶體的要求很小,只要能夠儲存下一個資料元素的記憶體塊都可以使用,因此不會造成碎片化。

總結起來就是:大小可以動態調整,增刪迅速,查詢較慢,資料元素所佔記憶體略多,不需要整塊記憶體塊,不會造成碎片化。

陣列與連結串列的選擇

通過以上分析,陣列連結串列對我們影響最大的幾點區別在於:

  • 陣列按位置查詢迅速,連結串列增刪方便
  • 陣列是固定大小,連結串列可以隨時擴充與縮減
  • 連結串列每個元素佔據記憶體略多於陣列
  • 陣列和連結串列在查詢方面表現都比較一般,耗時較長

在資料量很小,內容基本固定時,我們選擇何種資料結構的影響並不大。但當資料量較大時,如果我們需要對資料進行頻繁的插入刪除,我們應該選擇連結串列,如果我們需要頻繁的獲取某個位置的元素,我們應該選擇陣列。陣列與連結串列並沒有明確的優劣之分,根據不同的使用場景進行不同的選擇,才是這兩種結構使用的最佳方式。

上一篇:Java集合原始碼分析之開篇

下一篇:Java集合原始碼分析之基礎(二):雜湊表

本文到此就結束了,如果您喜歡我的文章,可以關注我的微信公眾號:大大紙飛機

或者掃描下方二維碼直接新增:

公眾號

您也可以關注我的github:https://github.com/LtLei/articles

程式設計之路,道阻且長。唯,路漫漫其修遠兮,吾將上下而求索。

相關文章