扩容是元素还是数组_数组是如何随机访问元素?数组下标为什么从0开始,而不是1?...
數組如何實現隨機訪問元素
什么是數組?
數組(Array)是一種線性表數據結構,它用一組連續的內存空間,來存儲相同類型的數據。
什么是線性表(Linear List)?
線性表就是數據排成一條線一樣的結構,每個線性表的數據最多只有前后兩個方向。
例如:數組,鏈表,隊列,棧 等都是線性表結構。
什么是非線性表?
例如:二叉樹,堆,圖,等,是非線性表,是因為,在非線性表中,數據之間并不是簡單的前后關系。
數組是如何隨機訪問數組元素?
數組是如何實現根據下標隨機訪問數組元素的嗎?
例如: int[]a=newint[10]
1,計算機給數組a[10],分配了一組連續的內存空間。
2,比如內存塊的首地址為 base_address=1000。
3,當計算給每個內存單元分配一個地址,計算機通過地址來訪問數據。當計算機需要訪問數組的某個元素的時候,會通過一個尋址公式來計算存儲的內存地址。
公式如下:
a[i]_address = base_address + i * data_type_sizearr[i] 首地址 = 數組內存塊首地址 + 數據類型大小 * i ,其中i為偏移量。
baseaddress:內存塊的首地址。datatype_size:數組中每個元素的大小,比如每個元素大小是4個字節。
1,數組使用二分法查找元素,時間復雜度是O(logn)。
2,根據下標隨機訪問的時間復雜度是O(1)。
低效的“插入”和“刪除”
插入
插入:從最好O(1) 最壞O(n) 平均O(n)
什么時候會是O(1)?
數組若無序,插入新的元素時,可以將第K個位置元素移動到數組末尾,把新的元素,插入到第k個位置,此處復雜度為O(1)。
例如:a[10] 數組存儲了5個元素: A B C D E
我們現在需要將元素 x 插入到第 3 個位置。我們只需要將 c 放入到 a[5],將 a[2] 賦值為 x 即可。
最后,數組中的元素如下: A,C,X,D,E,C。
什么時候會是最壞O(n)?
從數組開頭插入數據,所有的數據往后移一位,情況最差,時間復雜度為O(n) 。
每一位插入的概率一樣,所以平均時間復雜度為 (1+2+...+n)/n=(1+n)/2=O(n)。
刪除
刪除:從最好O(1) 最壞O(n) 平均O(n)
和插入數據類似,如果我們要刪除 K 個位置的數據,要保證內存的連續性,我們需要搬移 K 位置后的所有數據往前移動一位。
什么時候會是O(1)?
刪除開頭的數據
什么時候會是最壞O(n)?
同數組插入的原理類似
數組如何提高效率?
將多次刪除操作中集中在一起執行,可以先記錄已經刪除的數據,但是不進行數據遷移,而僅僅是記錄,當發現沒有更多空間存儲時,再執行真正的刪除操作,這樣減少數據搬移次數節省耗時。
這也是跟 JVM 標記清除垃圾回收算法的核心思想相似。
標記-整理垃圾回收算法。
在垃圾收集時此算法分為“標記”、“清除”兩個階段,先標記出需要回收的對象,再統一清除標記的對象。清除之后會產生大量不連續的內存碎片。
標記-整理垃圾回收算法
在標記完成之后讓所有存活的對象都向一端移動,然后直接清理掉邊界以外的內存。
用數組還是容器?
數組先指定容器大小,容器ArrayList可以動態擴容,并且封裝了好多方法,一旦超過存儲容量,擴容時比較耗時,因為涉及內存申請和數據復制搬移到擴容后的數組。
1,如果已知數據大小,且涉及的數據操作比較簡單,可以用數組。
2,比如已知 1 萬條數據要存入 ArrayList,我們就可以事先指定容器大小。
例如下代碼,就可以,省掉多次的,內存申請,和數據搬移操作
3,容器無法存儲基本類型,比如 int long 需要轉換成包裝類型,類型的轉換有性能消耗。
4,業務開發,使用容器足夠,追求性能,首先用數組。
為什么數組要從 0 開始編號,而不是1?
從偏移角度理解a[0] 0為偏移量,如果從1計數,會多出K-1。增加cpu負擔。為什么循環要寫成 for(inti=0;i<3;i++)而不是 for(inti=0;i<=2;i++)。第一個直接就可以算出3-0 = 3 有三個數據,而后者 2-0+1個數據,多出1個加法運算,很惱火。
參考:《數據結構與算法之美》
總結
以上是生活随笔為你收集整理的扩容是元素还是数组_数组是如何随机访问元素?数组下标为什么从0开始,而不是1?...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 1载波把32个信道按_OFDM技术:相比
- 下一篇: 休眠 关闭串口输出_C#实例:串口通讯