1. 程式人生 > >數組介紹

數組介紹

ESS 原因 數組 空間不夠 下標 針對 習慣 出現 最簡

什麽是數組?

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

數組如何實現隨機訪問?

基於數組的兩大特性:線性表結構和連續的內存空間和相同類型的數據,使得數組可以通過下標直接訪問數組元素,從而具有“隨機訪問”的特性。

具體實現方法:

當計算機需要隨機訪問數組中的某個元素時,通過尋址公式計算出該元素存儲的內存地址,尋址公式如下所示:

a[i]_address = base_address + i * data_type_size

其中 i 為數組元素的下標(從0開始),data_type_size 表示數組中每個元素的大小,假如數組中存儲的是 int 類型數據,那麽 data_type_size 就為4個字節。

數組查找的時間復雜度

根據下標隨機訪問的時間復雜度為 O(1)。

註意:前提條件是根據下標進行的隨機訪問,如果是在下標不確定的情況下查找某個元素,那麽即便是已經排好序的數組,你用二分查找,時間復雜度也是 O(logn)。

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

數組為了保持內存數據的連續性,會導致插入、刪除操作比較低效,具體是為什麽呢?

插入操作

每當在數組中插入一個新元素的時候,為了給這個新插入的元素挪出一個位置,我們可能需要移動大量的元素。

假設數組的長度為 n,如果在數組的末尾插入元素,那就不需要移動數組了,所以最好時間復雜度為 O(1)。但如果在數組的開頭插入元素,那所有的元素都要一次往右移動一位,所以最壞時間復雜度為 O(n)。

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

刪除操作

和插入數據類似,如果我們要刪除某個位置的數據,為了內存的連續性,也需要搬移數據。

類比插入數據,如果刪除數組末尾的數據,那麽就不需要移動數組了,所以最好時間復雜度為 O(1);如果刪除開頭的元素,則整個數組都要移動,所以最壞時間復雜度為 O(n);同理可知,平均時間復雜度為 O(n)。

警惕數組的訪問越界問題

數組越界在 C 語言中是一種未決行為,並沒有規定數組訪問越界時編譯器應該如何處理。因此,在 C 語言中出現數組訪問越界的情況時,會出現莫名其妙的邏輯錯誤,例如,訪問了非法地址、陷入死循環等等。

不同於 C 語言,Java 本身就會做數組越界檢查,比如下面幾行代碼,就會拋出 java.lang.ArrayIndexOutOfBoundsException。

1 int[] a = new int[3];
2 a[3] = 10;

容器能否完全替代數組?

針對數組類型,很多語言都提供了容器類。比如 Java 中的 ArrayList、C++ STL 中的 vector。

與數組相比,容器有哪些優勢呢?

以 Java 的 ArrayList 為例,ArrayList 最大的優勢就是可以將很多數組操作的細節封裝起來,比如前面所說的數組插入、刪除數據時需要移動其他數據等;另外,它還支持動態擴容。

我們在定義數組的時候通常需要預先指定大小,以便計算機分配連續的內存空間,當預先指定的空間不夠用時,則需要重新分配一塊更大的空間並將原來的數據復制過去,然後再繼續插入新的數據。如果使用 ArrayList,每次內存空間不夠用的時候,它都會講空間自動擴容為 1.5 倍大小,這樣我們就完全不需要關心底層的擴容邏輯了。

數組有哪些優勢?

1. 以 Java 的 ArrayList 為例,ArrayList 無法存儲基本數據類型,比如 int、long,需要封裝為 Integer、Long 類。這種時候,選用數組可減少一定的性能消耗。

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

總結一下

對於業務開發,直接使用容器就足夠了,只需要犧牲一點點的性能,就能省下大量時間。但如果是做一些非常底層的開發,比如開發網絡框架,性能的優化需要做到極致,這個時候就應該使用數組。

為什麽數組要從 0 開始編號?

前面我們講過尋址公式:

a[i]_address = base_address + i * data_type_size

所謂下標,其實是一個“偏移量”,如果數組從 1 開始計數,那我們計算數組元素 a[k] 的內存地址就會變為:

a[i]_address = base_address + (i-1) * data_type_size

對比兩個公式,我們不難發現,從 1 開始編號,每次隨機訪問數組元素都多了一次減法運算,對於 CPU 來說,就是多了一次減法指令,在一定程度上降低了一點效率。

還有一個歷史原因:C 語言設計者用 0 開始計數數組下標,之後的許多高級語言都沿用了這一習慣。

內容小結

  • 數組是最基礎、最簡單的數據結構。
  • 數組用一塊連續的內存空間來存儲相同類型的一組數據。
  • 數組最大的特點是支持隨機訪問,但其插入、刪除操作較為低效。
  • 在平時的業務開發中,我們可以使用編程語言提供的容器類來代替數組;但是對於底層的開發,直接使用該數組更有利用提升性能和效率。

數組介紹