1. 程式人生 > >【從0到1學演算法】 陣列和連結串列

【從0到1學演算法】 陣列和連結串列

今天講最基本的資料結構,陣列和連結串列。如果你已經滾瓜爛熟,可以跳過本文或選擇查缺補漏。

記憶體的工作原理

假設你正要去超市,需要寄存兩樣東西。這個超市的寄存櫃,一個抽屜只能放一個東西,所以你需要兩個抽屜。

將東西分別放到了1號和2號抽屜裡。

服務員將號碼牌給你後,就可以去shopping了,購物完,憑號碼牌拿東西即可。這大致就是計算機記憶體的工作原理,計算機記憶體就像很多抽屜,各個抽屜都有地址,根據地址儲存和訪問資料。

儲存單項資料時,只需要計算機提供一個儲存地址即可。當需要儲存多項資料時,會用到兩種基本方式---陣列和連結串列

假設你要編寫一個管理待辦事項的應用,需要將這些待辦事項儲存到記憶體中,用陣列還是連結串列?

陣列

使用陣列,就意味著所有待辦事項在記憶體中都是相連的。

如果你現在想新增第4個待辦事項,但後面那個抽屜放著別人的東西,這就難辦了。這種情況只能請求計算機重新分配記憶體(可容納4個待辦事項),再將所有事項移到那裡。

這裡還有個權宜之計“預留位置”:預先申請10個連續位置,以防需要新增待辦事項。這樣,只要不超過10個,就無需轉移。但它有兩個缺點:

1.請求額外記憶體可能用不上,導致浪費;

2.超過10個後,還是得轉移。

這是一個不錯的措施,但不是完美的方案。對於這種問題,我們可以用連結串列解決。

連結串列

使用連結串列,元素則可以儲存在記憶體的任何位置。

每個元素都會儲存下一個元素的記憶體地址。比如,"吃午飯"儲存下一個元素“玩滾地球”的記憶體地址13,而“玩滾地球”會儲存下一個元素“喝茶”的地址22,這樣便能將這幾項資料串在一塊了。

使用連結串列,根本不需要移動元素,元素隨便放哪都行。新增新元素時,也不需要”預留位置“,只要記憶體足夠,就能為連結串列分配記憶體。

索引

使用陣列和連結串列儲存資料,我們都會給元素編號,編號從0開始,這些元素的編號位置成為索引。

例如,下面的陣列,元素20在索引1處

讀取

陣列-隨機訪問

正因為陣列是順序儲存的,當知道起始地址,便能知道陣列中所有元素的地址,支援隨機訪問(可隨機讀取任意索引位置的值)

假設有一個數組,包含5個元素,起始地址為00,那麼我們便能簡單推算出第5個元素的地址是04

連結串列-順序訪問

而連結串列呢?元素是分開儲存的,無法推算出任意位置元素的地址,不支援隨機訪問,只能順序訪問(從第一個元素開始逐個讀取元素)。

假設有一個連結串列,儲存數值和位置如下,知道起始地址為01,但無法直接知道第5個元素的位置,因為不是順序儲存且每個元素只儲存了下一個元素的地址。

必須從頭遍歷,直到找到第5個位置的元素01>03>05>07>08。

所以,當需要隨機訪問,陣列是更好的選擇。

插入元素

陣列插入資料,必須將後面的元素後移(保持順序儲存),且有可能出現連續記憶體不足,這就得將整個陣列複製到其他地方

例如,插入“賣茶葉”到第3個位置

使用連結串列時,插入元素很簡單,只需修改它前一個元素的指向地址即可。

所以,當需要頻繁插入元素,連結串列是更好的選擇。

刪除

刪除元素呢?連結串列是更好的選,因為只需修改它前一個元素的指向地址即可。

而使用陣列時,刪除元素後,必須將後面的元素都向前移(保持順序儲存)。

常見操作的執行時間

需要注意的是,連結串列刪除元素時,當能夠立即刪除元素時,執行時間才為O(1), 因為通常我們都記錄了連結串列的第一個和最後一個元素。其他情況均為O(n),因為需要通過順序遍歷再刪除。

總結

陣列

儲存位置:順序儲存。

優點:支援隨機訪問,讀取速度快。

缺點:插入和刪除資料較慢,需要移動元素。

連結串列

儲存位置:分開儲存,每個元素都儲存了下一個元素的地址。

優點:插入和刪除資料快,無需移動元素,只需修改它前面元素的指向地址即可。

缺點:只支援順序訪問,讀取速度較慢。

讀取多,插入少,用陣列。

讀取少,插入多,用連結串列。

但在實際應用中,陣列用的更多一,因為它支援隨機讀取。


文章首發於公眾號【KEN DO EVERTHING】
本公眾號專注於java相關技術,但不限於java、mysql、python、面試技巧、生活感悟等。分享優質博文,技術乾貨,學習資源等優質內容。
歡迎關注,一起學習,共成長