1. 程式人生 > >演算法筆記-陣列

演算法筆記-陣列

資料結構之陣列

本文創作靈感來源於 極客時間 王爭老師的《資料結構與演算法之美》課程,通過課後反思以及借鑑各位學友的發言總結,現整理出自己的知識架構,以便日後溫故知新,查漏補缺。

是什麼

什麼是陣列
  • 陣列是一種線性表資料結構,在記憶體空間中佔據連續的空間,並且儲存著相同型別的資料。

為什麼

為什麼要出現數組這種資料結構
  • 把相同型別的一系列資料統一編制到某一個組別中,這樣就可以通過陣列名+索引號簡單快捷的操作大量資料。

怎麼辦

怎麼學習陣列
  • 學習陣列前,我們先理解陣列定義中的兩個概念。
  • 線性表:線性表結構規定了陣列只有前後兩個方向。連結串列,佇列,棧也屬於線性表資料結構。而與之相對立的就是非線性表,例如:二叉樹,堆,圖等,這些資料結構中,資料與資料之間的關係,並非簡單的前後關係。
  • 連續的記憶體空間和相同的資料型別:連續的記憶體空間,說明了陣列中的元素可以隨機訪問,相同的資料型別表明了陣列用法的限制,只能儲存相同型別資料。
陣列的插入和刪除
  • 有序陣列的插入:在有序陣列中插入資料,如果在陣列第一個位置插入資料,那麼陣列中原有的所有元素都需要往後移動一位,時間複雜度為 O ( n )
    O(n)
    。如果在陣列的最後一個位置插入資料,時間複雜度為 O ( 1 ) O(1) 。平均時間複雜度就是 O
    ( n ) O(n)
    ,出現這種現象是因為陣列的儲存空間是連續的。
  • 無序陣列的插入:首先,我們可以按照有序陣列的插入方法插入資料,但是時間複雜度為 O ( n ) O(n) ,接著我們對插入方法進行如下優化。當我們往陣列中除末尾以外的任何位置插入資料的時候,可以把要插入位置的已有元素放在陣列末尾,要插入的資料放在蓋插入位置,那麼時間複雜度就一直是 O ( 1 ) O(1)
  • 直接刪除:由於資料的儲存空間是連續的,所以我們刪除陣列中除末尾以為的任何元素都需要將後續元素往前移動一位,那麼平均時間複雜度就是 O ( n ) O(n)
  • 高效刪除:對直接刪除方法進行優化,我們可以對要刪除的元素做刪除標記,等到要刪除的元素個數積累到一定數量的時候,我們再進行統一刪除,這樣平均時間複雜度一定小於 O ( n ) O(n) ,刪除操作變得高效了。這種標記刪除正是JVM標記清除回收垃圾演算法的核心思想。
陣列的容器
  • 在JAVA語言中,陣列的容器類就是 ArrayList 。ArrayList 封裝了陣列的基本操作,同時提供了陣列的動態擴容。所謂的動態擴容就是在當前陣列記憶體空間用完之後,重新申請比當前空間大1.5倍的新陣列,並把舊陣列的元素搬移到新的陣列中。
  • 優缺點:陣列的容器封裝了陣列的基本操作方法,使得我們操作資料更方便快捷。但是容器類不能儲存基本資料型別,需要對基本型別進行裝箱然後才能儲存,這樣就增加了裝箱拆箱的效能損耗。
  • 用法建議:王爭老師給出的建議:如果開發的是一些底層框架,追求效能,那就選擇陣列。如果事先已知陣列的大小,無需擴容,那就直接使用陣列。當表示多維陣列的時候,用陣列更加直觀。但是在業務開發過程中,直接使用容器類更加方便省時,損耗一丟丟效能,帶來工作上的方便,還是很划得來。
陣列的下標為什麼是從0開始
  • 一個是歷史原因:C語言設計之初就是從0開始,後續的高階語言也遵從了C語言的設計風格。
  • 二:陣列中的下標其實代表的是當前元素地址的偏移量,由於陣列是連續空間,後續元素儲存的位置都是相對於首地址的偏移量,第一個元素偏移量就是0,第二個元素偏移量就是1,這樣CPU定址的時候:地址=佔用記憶體 * 陣列下標+首地址。如果下標是從1開始,那麼:地址=佔用記憶體 * (陣列下標-1)+首地址。

總結

陣列的查詢時間複雜度並不是 O ( 1 ) O(1) ,陣列支援隨機訪問,根據下標隨機訪問的時間複雜度並是 O ( 1 ) O(1)