數據結構——數組

數組是一種線性表數據結構。它用一組連續的內存空間,來存儲一組具有相同類型的數據

線性表

線性表就是數據排成像一條線一樣的結構。每個線性表上的數據最多隻有前和後兩個方向

除了數組,鏈表、隊列、棧等也是線性表結構。

非線性表

與之對應的就是非線性表,比如二叉樹、堆、圖等。

之所以叫非線性,是因爲在非線性表中,數據之間並不是簡單的前後關係。

連續的內存空間和相同類型的數據

數組有着連續的內存空間相同類型的數據兩個限制,這兩個限制有利有弊。

數組的很多操作變得非常低效,但是同時也讓數組有了“隨機訪問”的特性

數組支持隨機訪問,根據下標隨機訪問的時間複雜度爲 O(1)。

低效的“插入”和“刪除”

要想在數組中刪除、插入一個數據,爲了保證連續性,就需要做大量的數據搬移工作。

假設數組的長度爲 n,現在,如果我們需要將一個數據插入到數組中的第 k 個位置。

爲了把第 k 個位置騰出來,給新來的數據,我們需要將第 k~n 這部分的元素都順序地往後挪一位。

如果在數組的末尾插入元素,那就不需要移動數據了,這時的時間複雜度爲 O(1)。

但如果在數組的開頭插入元素,那所有的數據都需要依次往後移動一位,所以最壞時間複雜度是 O(n)。

因爲我們在每個位置插入元素的概率是一樣的,所以平均情況時間複雜度爲 (1+2+…n)/n=O(n)。

如果數組中存儲的數據並沒有任何規律,數組只是被當作一個存儲數據的集合。在這種情況下,要將某個數據插入到第 k 個位置,爲了避免大規模的數據搬移,我們還有一個簡單的辦法就是,直接將第 k 位的數據搬移到數組元素的最後,把新的元素直接放入第 k 個位置。

利用這種處理技巧,在特定場景下,在第 k 個位置插入一個元素的時間複雜度就會降爲 O(1)。

 

如果我們要刪除第 k 個位置的數據,爲了內存的連續性,也需要搬移數據,不然中間就會出現空洞,內存就不連續了。

和插入類似,如果刪除數組末尾的數據,則最好情況時間複雜度爲 O(1)。

如果刪除開頭的數據,則最壞情況時間複雜度爲 O(n);平均情況時間複雜度也爲 O(n)。

 

長度固定,警惕數組的訪問越界問題

數組越界在 C 語言中是一種未決行爲,並沒有規定數組訪問越界時編譯器應該如何處理。

因爲,訪問數組的本質就是訪問一段連續內存,只要數組通過偏移計算得到的內存地址是可用的,那麼程序就可能不會報任何錯誤。這種情況下,一般都會出現莫名其妙的邏輯錯誤,debug 的難度非常的大。

很多計算機病毒也正是利用到了代碼中的數組越界可以訪問非法地址的漏洞,來攻擊系統,所以寫代碼的時候一定要警惕數組越界。

並非所有的語言都像 C 一樣,把數組越界檢查的工作丟給程序員來做。

Java 本身就會做越界檢查,數組越界就會拋出 java.lang.ArrayIndexOutOfBoundsException。

 

容器能否完全替代數組

拿 Java 語言來舉例,ArrayList 最大的優勢就是可以將很多數組操作的細節封裝起來。比如前面提到的數組插入、刪除數據時需要搬移其他數據等。

另外,它還有一個優勢,就是支持動態擴容

數組本身在定義的時候需要預先指定大小,因爲需要分配連續的內存空間。如果我們申請了大小爲 10 的數組,當第 11 個數據需要存儲到數組中時,我們就需要重新分配一塊更大的空間,將原來的數據複製過去,然後再將新的數據插入。

如果使用 ArrayList,我們就完全不需要關心底層的擴容邏輯,ArrayList 已經幫我們實現好了。每次存儲空間不夠的時候,它都會將空間自動擴容爲 1.5 倍大小。

這裏需要注意一點,因爲擴容操作涉及內存申請和數據搬移,是比較耗時的。所以,如果事先能確定需要存儲的數據大小,最好在創建 ArrayList 的時候事先指定數據大小。

 

有些時候,用數組會更合適些:

1.Java ArrayList 無法存儲基本類型,比如 int、long,需要封裝爲 Integer、Long 類,而 Autoboxing、Unboxing 則有一定的性能消耗,所以如果特別關注性能,或者希望使用基本類型,就可以選用數組。

2. 如果數據大小事先已知,並且對數據的操作非常簡單,用不到 ArrayList 提供的大部分方法,也可以直接使用數組。

3. 還有一個是我個人的喜好,當要表示多維數組時,用數組往往會更加直觀。比如 Object[][] array;而用容器的話則需要這樣定義:ArrayList<ArrayList<object> > array

對於業務開發,直接使用容器就足夠了,省時省力。畢竟損耗一丟丟性能,完全不會影響到系統整體的性能。

但如果你是做一些非常底層的開發,比如開發網絡框架,性能的優化需要做到極致,這個時候數組就會優於容器,成爲首選。

 

 

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