數組是一個線性表數據結構。它用一段連續的內存地址空間,來存儲一些相同類型的數據。 從上面的定義,咱們不難看出幾個關鍵詞。算法
線性表:顧名思義,線性表就是數據排列成一條線的數據結構。每個線性表只有先後兩個方向。隊列、鏈表、數組、棧都是線性表結構。數組
連續的內存空間和相同類型的數據:正是由於有了這兩個限制,才使數組有了,能夠根據數組的下標隨機訪問的特性。可是也由於連續的內存空間的限制,致使數組在進行刪除和插入操做的時候,很是的低效。數據結構
首先咱們定義一個數組是,例如:int[] a=new int[10]
,當咱們定義的時候,計算機會給數組a[]分配一塊連續的內存地址。當我經過數組下標去訪問時,計算機會經過尋址公式a[i]_address = base_address + i * data_type_size
計算出數據在內存中的地址,進行訪問。其中,base_address是內存首地址,data_type_size表示數組每一個元素的大小。好比:啊a[]是int類型,因此data_type_size,就是4個字節。性能
爲了保證數組的連續內存空間性,在對中間的元素進行插入和刪除的時候,須要將數組中其餘元素移動位置。這樣的作法會浪費一些性能,與鏈表的插入和刪除相比,十分低效。學習
在一個有序的數組中,往下標爲3的位置插入元素,須要將下標4到末尾的數據總體向後挪移。若是在一個無序的數組中,往下標爲3的位置插入元素,最好的辦法是將下標爲3的元素放到數組的末尾,在將元素插入,減小元素挪到帶來的性能損耗。優化
和插入相似,刪除數組中的一個元素,爲了保證內存空間的連續性,須要進行數據的挪移。咱們也能夠記錄下每次刪除的元素,但不真正的去刪除挪移元素,到數組已經滿了之後,在進行一次進行數據的刪除挪移。這樣能夠大大減小元素搬移帶來的性能消耗。有點像垃圾回收機制。指針
在JAVA中提供了數組的類型的容器,好比:ArrayList。那麼數組和ArrayList有哪些優缺點呢?code
ArrayList最大的優勢是將數組的插入、刪除和查詢等一些操做進行了封裝,在使用的時候不須要考慮元素的搬移。另外一個比較大的優勢是,ArrayList支持動態擴容。因爲在數組在定義的時候,計算機須要根據數組的大小分配一塊連續的內存空間,因此須要提早定義數組的大小。ArrayList在底層進行了自動擴容實現,當元素大於ArrayList大小時,它會將空間擴大到1.5倍大小,而後將數據複製到新的數組。cdn
鏈表是一種物理存儲單元上非連續、非順序的存儲結構,不須要一塊連續的內存空間,他經過鏈表的指針有次序的將零散的內存空間鏈接。最多見的鏈表結構有:單鏈表、雙向鏈表和循環鏈表。blog
單鏈表顧名思義,它的鏈表方向是單向的,對於鏈表的訪問只能從頭部開始,這也致使了鏈表的查詢效率低下。
上圖是一個單向鏈表,它有兩個結點比較特殊,一個是第一個結點,叫頭結點,用來記錄鏈表的基結點;另外一個是最後一個結點,叫尾結點,它比較特殊,並非指向下一個結點,而是指向一個NULL地址。從上面數組咱們知道,因爲內存空間連續的限制,元素刪除和插入須要數據搬移。可是鏈表的內存空間不須要連續,因此它的插入和刪除操做十分的高效。
對於鏈表的查詢,咱們只須要相鄰結點的指針變化。
上圖是一個單向鏈表的刪除過程,從圖上咱們能夠知道,將鏈表中的元素刪除,將這個元素刪除,而後,在將前結點的Next指針,指向它的後結點就OK了,十分的高效。插入操做也是相似,將前結點的Next指針指向,插入的元素,將插入的指針,指向它。
循環鏈表是一種特殊的單鏈表。它與單鏈表的惟一區別是,尾結點的Next指針不是指向一個Null地址,而是,指向了鏈表的頭結點,造成了一個閉環,達到了循環的目的。其實確切的說這是一種單向循環鏈表。
與上面的單鏈表不一樣,雙向鏈表元素之間是雙向的,表現形式也比單鏈表複雜一點。它的每個結點不止有後繼指針Next,還有一個前驅指針Pre。從這一點可知,一個雙向鏈表的結點比單向鏈表多一個前驅指針,這也意味着它的每個結點須要更多的空間去存儲前驅指針。
插入和刪除操做與單向鏈表相似,只須要處理好前驅指針和後繼指針的指向。
咱們知道,單向鏈表想要刪除一個元素,須要從頭部開始查詢直到找到該元素,而後進行刪除,指針重新指向,在這一點上雙向鏈表和單向鏈表是一致的。可是咱們若是想要刪除一個元素的前驅結點,單向鏈表由於沒有前驅指針,須要再從頭遍歷,消耗時間,雙向鏈表就能夠直接找到前驅結點,並刪除。
其實這是一種空間換時間的思路。使用了雙向鏈表佔用了多的空間,節約了時間。這種在咱們內存足夠的狀況下,優化算法的執行時間有很好的的幫助。
因爲內存空間連續性的不一樣,鏈表適合插入、刪除操做,而數組則更加適合根據下標的查詢。
最後,本文爲學習記錄文,但願能夠堅持下去。