1. 程式人生 > 其它 >線性資料結構概覽

線性資料結構概覽

線性資料結構

1.陣列

陣列(Array)是一種線性表資料結構。它用一組連續的記憶體空間,來儲存一組具有相同型別的資料。
陣列支援隨機訪問,根據下標隨機訪問的時間複雜度為 O(1)。
ArrayList 無法儲存基本型別,比如 int、long,需要封裝為 Integer、Long 類,而 Autoboxing、Unboxing 則有一定的效能消耗

2.連結串列

它並不需要一塊連續的記憶體空間,它通過“指標”將一組零散的記憶體塊串聯起來使用。
單鏈表、雙向連結串列和迴圈連結串列:單鏈表的尾結點指標指向空地址,表示這就是最後的結點了。而迴圈連結串列的尾結點指標是指向連結串列的頭結點。單向連結串列只有一個方向,結點只有一個後繼指標next指向後面的結點。而雙向連結串列,顧名思義,它支援兩個方向,每個結點不止有一個後繼指標next指向後面的結點,還有一個前驅指標prev指向前面的結點,用空間換時間的設計思想。
針對連結串列的插入和刪除操作,我們只需要考慮相鄰結點的指標改變,所以對應的時間複雜度是 O(1),連結串列隨機訪問需要 O(n) 的時間複雜度。

在實際的軟體開發中,從連結串列中刪除一個數據無外乎這兩種情況:
1.刪除結點中“值等於某個給定值”的結點。 單向連結串列查詢O(n)刪除O(n),雙向連結串列查詢O(n)刪除O(1)
2.刪除給定指標指向的結點。 單向連結串列 O(n),雙向連結串列O(1)

陣列簡單易用,在實現上使用的是連續的記憶體空間,可以藉助CPU的快取機制,預讀陣列中的資料,所以訪問效率更高。而連結串列在記憶體中並不是連續儲存,所以對CPU 快取不友好,沒辦法有效預讀。陣列的缺點是大小固定,一經宣告就要佔用整塊連續記憶體空間,連結串列本身沒有大小的限制,天然地支援動態擴容,我覺得這也是它與陣列最大的區別。

3.棧

後進者先出,先進者後出,這就是典型的“棧”結構。就像一疊盤子。
當某個資料集合只涉及在一端插入和刪除資料,並且滿足後進先出、先進後出的特性,這時我們就應該首選“棧”這種資料結構。
用陣列實現的棧,我們叫作順序棧,用連結串列實現的棧,我們叫作鏈式棧。

4.佇列

先進者先出。用陣列實現的佇列叫作順序佇列,用連結串列實現的佇列叫作鏈式佇列。
阻塞佇列:在佇列為空的時候,從隊頭取資料會被阻塞,如果佇列已經滿了,那麼插入資料的操作就會被阻塞;
執行緒安全的佇列我們叫作併發佇列;
實際上,對於大部分資源有限的場景,當沒有空閒資源時,基本上都可以通過“佇列”這種資料結構來實現請求排隊

5.散列表

鍵 --雜湊函式--> 雜湊值 存入陣列,雜湊值是下標,鍵是陣列值
散列表用的是陣列支援按照下標隨機訪問資料的特性,所以散列表其實就是陣列的一種擴充套件,由陣列演化而來。可以說,如果沒有陣列,就沒有散列表。
業界著名的MD5、SHA、CRC等雜湊演算法,也無法完全避免這種雜湊衝突。Java 中 LinkedHashMap 就採用了連結串列法解決衝突,ThreadLocalMap 是通過線性探測的開放定址法來解決衝突
Java 中的 HashMap 這樣一個工業級的散列表:預設的初始大小是 16,最大裝載因子預設是 0.75,每次擴容都會擴容為原來的兩倍大小,底層採用連結串列法來解決衝突,當連結串列長度太長(預設超過8)時,連結串列就轉換為紅黑樹,當紅黑樹結點個數少於 8 個的時候,又會將紅黑樹轉化為連結串列

6.跳錶

這種連結串列加多級索引的結構,就是跳錶
建立了很多索引,空間換時間。查詢時間複雜度 logn,插入時間複雜度也是logn,空間複雜度O(n)。
索引儲存的只是引用,相比物件很小,所以不必在意索引所佔空間。

播種和收穫通常不在一個季節,而中間的過程叫做堅持~