陣列(array)是一種線性表資料結構。它用一組連續的記憶體空間,來儲存一組具有相同型別的資料。在面試的時候,面試官常常會問陣列和鍊錶的區別,很多人都回答說,「鍊錶適合插入、刪除,時間複雜度 o(1);陣列適合查詢,查詢時間複雜度為 o(1)」。實際上,這種表述是不準確的。陣列是適合查詢操作,但是查詢的時間複雜度並不為 o(1)。即便是排好序的陣列,你用二分查詢,時間複雜度也是 o(logn)。所以,正確的表述應該是,鍊錶適合插入、刪除,時間複雜度 o(1),陣列支援隨機訪問,根據下標隨機訪問的時間複雜度為 o(1)。
目錄
插入操作
刪除操作
乙個問題
內容小結
假設陣列的長度為 n且是有序的,現在,如果我們需要將乙個資料插入到陣列中的第 k 個位置。為了把第 k 個位置騰出來且保證順序,給新來的資料,我們需要將第 k~n 這部分的元素都順序地往後挪一位。那插入操作的時間複雜度是多少呢?
最好情況複雜度:在陣列的末尾插入元素,不需要移動資料,這時的時間複雜度為 o(1)。
最壞情況複雜度:在陣列的開頭插入元素,所有的資料都需要依次往後移動一位,所以最壞時間複雜度是 o(n)。
平均情況複雜度:因為在每個位置插入元素的概率是一樣的,所以平均情況時間複雜度為 (1+2+...n)/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)。這個處理思想在快排中也會用到。
跟插入資料類似,如果我們要刪除第 k 個位置的資料,為了記憶體的連續性,也需要搬移資料,不然中間就會出現空洞,記憶體就不連續了。
和插入類似,如果刪除陣列末尾的資料,則最好情況時間複雜度為 o(1);如果刪除開頭的資料,則最壞情況時間複雜度為 o(n);平均情況時間複雜度也為 o(n)。
當然為了提高效率,我們可以將多個刪除操作合併在一起 ,以提高刪除效率。
c++ stl 中為我們提供了vector來封裝陣列,其支援動態擴容,每次擴容的大小為當前大小的1.5倍以減少拷貝操作。
為什麼大多數程式語言中,陣列要從 0 開始編號,而不是從 1 開始呢?a[k]_address = base_address + (k-1)*type_size
對比兩個公式,我們不難發現,從 1 開始編號,每次隨機訪問陣列元素都多了一次減法運算,對於 cpu 來說,就是多了一次減法指令。陣列作為非常基礎的資料結構,通過下標隨機訪問陣列元素又是其非常基礎的程式設計操作,效率的優化就要盡可能做到極致。所以為了減少一次減法操作,陣列選擇了從 0 開始編號,而不是從 1 開始。a[k]_address = base_address + k*type_size
當然歷史原因也佔了很大部分。
陣列用一塊連續的記憶體空間,來儲存相同型別的一組資料,最大的特點就是支援隨機訪問,但插入、刪除操作也因此變得比較低效,平均情況時間複雜度為 o(n)。在平時的業務開發中,我們可以直接使用程式語言提供的容器類,例如stl的vector,但是,如果是特別底層的開發,直接使用陣列可能會更合適。
資料結構與演算法之美
什麼是資料結構?什麼是演算法 狹義重點 複雜度分析 方法 邊學邊練,適度刷題 複雜度分析 時間複雜度 常見時間複雜度 非多項式量級 非常低效的演算法 空間複雜度 漸進空間複雜度,表示演算法的儲存空間和資料規模的增長關係 最好情況時間複雜度 理想情況的時間複雜度 最壞情況時間複雜度 最糟糕的情況下的時...
資料結構與演算法之美(筆記1)陣列
鍊錶適合插入,刪除,時間複雜度是o 1 陣列支援隨機訪問,根據下標隨機訪問的時間複雜度是o 1 插入操作 假設陣列的長度為 n,現在,如果我們需要將乙個資料插入到陣列中的第k個位置。為了把第k個位置騰出來,我們需要把 k後的 n k 位置順序向後移動一位。最好時間複雜度 在最後一位插入,時間複雜度為...
資料結構與演算法之美 開篇
資料結構與演算法,是計算機的核心課程之一,是程式設計師武功體系的內功,想成為武林高手必須內功過硬,作為乙個非科班碼農,面試時因為內功不強而碰壁數次,使我真實的體驗到學好資料結構與演算法的重要性,為了不在這個方面繼續碰壁,也為了能在軟體開發工程師的道路上走的更遠更快,我決心集中精力學習突破這道關口 以...