數組(Array)是一種線性表數據結構。它用一組連續的內存空間,來存儲一組具有相同類型的數據。
線性表(Linear List)就是數據排成像一條線一樣的結構。每個線性表上的數據最多只有兩個方向。除了數組,鏈表、隊列、棧也是線性表結構。
與線性表對立的是非線性表,比如二叉樹、堆、圖等。之所以叫非線性,是因為,在非線性表中,數據之間並不是簡單的前后關系。
連續的內存空間和相同的數據類型:
數據根據下標隨機訪問的時間復雜度為 O(1)
數據的插入和刪除很低效:
- 如果刪除數組末尾的數據,最好情況時間復雜度為 O(1)
- 如果刪除開頭的數據,則最壞情況時間復雜度為 O(n)
- 平均情況時間復雜度也為 O(n)。
如果數組是排好序的,時間復雜度如上;如果不是排好序的,可以用下面的辦法:
假設數組 a[10] 中存儲了如下 5 個元素:a,b,c,d,e。
我們現在需要將元素 x 插入到第 3 個位置。我們只需要將 c 放入到 a[5],將 a[2] 賦值為 x 即可。最后,數組中的元素如下: a,b,x,d,e,c。
使用這種技巧:在特定的場景下,在第K個位置插入一個元素的時間復雜度就會降為O(1)
什么情況下使用數據?
- Java ArrayList 無法存儲基本類型,比如int、long,需要封裝未Integer、Long類,而Autoboxing、Unboxing則有一定的性能消耗;所以如果特別關注性能,或者希望使用基本類型,就可以選擇數據。
- 如果數據大小事先已知,並且對數據的操作非常簡單,用不到ArrayList提供的大部分方法,也可以直接使用數組。
- 當表示多維數組時,用數組往往會更加直觀,比如 Object[][] array;而容器的話需要這樣定義:ArrayList<ArrayList>array。
為什么大多數編程語言中,數組要從0開始編號,而不是1開始呢?
從數組的存儲模型上來看,“下標”最確切的定義應該是“偏移量(offset)”。
如果用a代表數組的首地址,a[0]就是偏移量為0的位置,也就是首地址,a[k]就表示偏移量k個 type_size 的位置,所以計算 a[k] 的內存地址只需要用這個公式:
a[k]_address = base_address + k * type_size
但是,如果數組從 1 開始計數,那我們計算數組元素 a[k] 的內存地址就會變為:
a[k]_address = base_address + (k-1)*type_size
如果從 1 開始編號,每次隨機訪問數組元素都多了一次減法運算,對CPU來說就是多了一次減法指令。