1. 程式人生 > >數據結構之數組

數據結構之數組

也會 插入 暫時 true tostring eof 空間不足 話題 n)

什麽是數組

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

下面是兩個值得註意的概念:

1. 線性表(linear list)

線性表,即數據的邏輯結構是線性的。每個線性表中的數據最多只有向前和向後兩個方向。典型的線性表有數組、鏈表、隊列和棧。

和線性表相對應的就是非線性表,即數據之間不是簡單的前後關系。如樹、堆、圖等。

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

這使數組具有一個堪稱“殺手鐧”的特性 ——“隨機訪問”,即可以通過下標隨機訪問數組元素。我們知道,計算機會給每個內存單元分配一個地址,然後通過地址來訪問內存中的數據。當計算機需要訪問數組中的某個元素時,就會通過下面的尋址公式,計算出存儲該元素的內存地址:

a[i]_address = base_address + i * data_type_size

其中,data_type_size 是數組中每個元素的大小,base_address 是內存塊的首地址。這樣,就可以用 O(1) 的時間復雜度獲取到下標為 i 的數組元素。

當然,有利就有弊,這一特性使得數組的很多操作變得低效,比如插入、刪除操作,為了保證連續性,需要做大量的數據搬移工作。

低效的插入和刪除

下面來看看,為什麽數組的插入和刪除操作是低效的,又有哪些改進方法呢?

1. 插入

假設數組長度為 n,要在第 k 位插入一個元素。那麽就需要將第 k ~ n 位元素順序後移,然後將新元素插入第 k 位。

如果 k = n - 1,則不需要再移動數據,此時時間復雜度為 O(1);如果 k = 0,則需要移動所有的數據,此時時間復雜度為 O(n)。用前一篇文章的分析方法(算法復雜度分析(下)),可知平均時間復雜度為:

(1 + 2 + ... + n) / n = O(n)

所以,數組的插入操作平均時間復雜度為 O(n),是一項低效的操作。

但是,如果數組中存儲的數據沒有任何規律,插入後不需要保持原來的順序,則可以進行如下操作:

直接將第 k 位的數據搬移到數組元素最後,然後把新的元素直接放在第 k 位。

這樣,時間復雜度就被降為了 O(1)。這個思想在快排中也會用到。

2. 刪除

和插入操作類似,如果要刪除第 k 位的元素,為了內存的連續性,也需要搬移數據,否則中間就會出現空洞,內存就不連續了。容易分析出,刪除操作的平均時間復雜度也為 O(n)。

事實上,我們可以將多次刪除操作集中在一起執行,先標記下已經刪除的數據,然後在某些條件下(比如沒有更多空間存儲數據時),統一執行真正的刪除操作,這樣就大大減少了刪除操作導致的數據搬移。

這種標記清除思想在其他地方也有所應用,比如垃圾回收中的標記清除算法。

數組越界問題

訪問數組的本質是訪問一段連續內存,只要數組通過偏移計算得到的內存地址都是可用的,那麽程序就可能不會報任何錯誤。

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

JavaScript 中的數組

作為一名前端,最後重點講一講 JavaScript 中的數組。

1. 不是在連續內存空間中存儲同類型數據

JavaScript 中的數組是一種引用數據類型(也叫復雜數據類型),它其實是一種對象,繼承於 Object,存儲與堆內存中。

Array.prototype.__proto__ === Object.prototype    // true

JavaScript 中可以通過數組的 length 屬性來獲取其長度:

arr.length

而 C 中需要使用這種方法:

sizeof(arr) / sizeof(arr[0])

python 中則是:

len(arr)

JavaScript 中的數組本質上是 key 為 ‘0‘, ‘1‘, ‘2‘, ... 的對象,對應的 value 可以為任意值。這樣的話,就可以很容易解釋下面這種現象:

var arr = [‘a‘, 1]
var key = { toString: function () { return ‘1‘ }}
key in arr    // true

2. 插入、刪除的性能問題

很慚愧,學藝不精,這個話題暫時就不發表評論了,以免誤人子弟。感興趣的同學可以移步這裏:https://stackoverflow.com/questions/8423493/what-is-the-performance-of-objects-arrays-in-javascript-specifically-for-googl

3. 不會有數組越界問題

JavaScript 數組空間不足時,會自動進行擴容操作,不會出現數組越界問題。具體分析可以參考這裏:https://zhuanlan.zhihu.com/p/26388217


本文是《數據結構與算法之美》的讀書筆記,首發於微信公眾號《代碼寫完了》

技術分享圖片

技術分享圖片

數據結構之數組