1. 程式人生 > >資料結構與算法系列4--陣列

資料結構與算法系列4--陣列

什麼是陣列?

陣列(Array)是一種線性表資料結構。它用一組連續的記憶體空間,來儲存一組具有相同型別的資料。陣列的一個最大特性就是支援下標隨機訪問陣列元素。
補充:
線性表就是資料排成像一條線一樣的結構。每個線性表上的資料最多隻有前和後兩個方向。其實除了陣列,連結串列、佇列、棧等也是線性表結構。
而與它相對立的概念是非線性表,比如二叉樹、堆、圖等。之所以叫非線性,是因為,在非線性表中,資料之間並不是簡單的前後關係。

陣列是如何實現根據下標隨機訪問陣列元素的?

我們拿一個長度為 10 的 int 型別的陣列 int[] a = new int[10] 來舉例。我們在宣告此陣列時,計算機會給我們分配好一塊連續的記憶體空間,這裡我們假設分配的地址是1000~1039,而此時a存放的就是記憶體塊的首地址 base_address = 1000這個地址,那具體怎麼根據下標訪問元素呢?
當計算機需要隨機訪問陣列中的某個元素時,它會首先通過下面的定址公式,計算出該元素儲存的記憶體地址:

a[i]_address = base_address + i * data_type_size

其中 data_type_size 表示陣列中每個元素的大小。我們舉的這個例子裡,陣列中儲存的是 int 型別資料,所以 data_type_size 就為 4 個位元組。通過這個公式,我們就可以根據下標值計算出每個元素的存放的地址,進而拿到該資料,如我們訪問a[0],即為訪問首地址下的元素,其他的以此類推。

陣列的優點

支援隨機訪問,根據下標隨機訪問的時間複雜度為 O(1)。所以陣列適合查詢。

陣列的缺點

插入和刪除慢,時間複雜度為O(n)。這點剛好和連結串列相反,連結串列的插入和刪除快,時間複雜度為O(1)。

為何陣列插入和刪除低效?

插入:
若有一元素想往int[n]的第k個位置插入資料,需要在k-n的位置往後移。
最好情況時間複雜度 O(1)
最壞情況複雜度為O(n)
平均負責度為O(n)
刪除:
與插入類似,為了保持記憶體的連續性。
最好情況時間複雜度 O(1)
最壞情況複雜度為O(n)
平均負責度為O(n)

如何對陣列插入和刪除操作進行優化?

插入優化:如果陣列中儲存的資料不是有序的,也就是無規律的情況下,假設要在第k個位置插入資料,則可以將第k個位置的資料移到最後,然後將資料直接插入在第K個位置上。這樣時間複雜度就將為 O(1)了。
**刪除優化:**將多次刪除操作集中在一起執行,對要刪除的資料可以先記錄下來,不是馬上刪除,而僅僅是記錄,只有當沒有更多的儲存空間時,再執行真正的刪除操作。這也是 JVM 標記清除垃圾回收演算法的核心思想。

容器和陣列的選擇?

陣列先指定了空間大小
容器如ArrayList可以動態擴容。
1.希望儲存基本型別資料,可以用陣列
2.事先知道資料大小,並且操作簡單,可以用陣列
3.對於業務開發,直接使用容器就足夠了,省時省力。畢竟損耗一丟丟效能,完全不會影響到系統整體的效能。但如果你是做一些非常底層的開發,比如開發網路框架,效能的優化需要做到極致,這個時候陣列就會優於容器,成為首選。

為什麼陣列要從 0 開始編號?

由於陣列是通過定址公式,計算出該元素儲存的記憶體地址:
a[i]_address = base_address + i * data_type_size
如果陣列是從 1 開始計數,那麼就會變成:
a[i]_address = base_address + (i-1)* data_type_size
這樣對於CPU來說,就多了一次減法的指令。為了儘可能的快,所以不採取這種方式。