小夕说,不了解动态空间增长的程序喵都是假喵(下)
小夕在本系列前兩篇文章中為大家介紹了各類數據結構的擴容策略,且在上篇文末,小夕提到了加倍式擴容中,倍率采用2并不是最優的,為什么呢?有沒有最優倍率呢?
?
內存復用
如果倍率采用2甚至更大的數,那么被開辟過的舊空間永遠都不會被新開辟的空間利用。小夕舉個栗子。
?
if(倍率≥2){
那么以下是小夕為大家畫的三次擴容后的內存塊的占用情況(小夕用PPT畫的,好麻煩的喵,讀者喵有好用的輕量級畫矢量圖的軟件記得推薦給小夕哦~)
?
?
上圖中,內存塊一共有15個字節。粉色實心框是數據結構占用的內存塊,空心框是空閑的內存。
?
假如一開始數據結構的大小是1字節,占用了0xFF00這個字節,如圖中第一列。然后第一次擴容后數據結構大小變成2字節,無法利用之前的舊內存空間。
同樣,第二次擴容,第三次擴容后,數據結構的大小總是要比之前累計占用的舊內存空間之和還要大,總是大1個字節,所以永遠都無法重新利用之前的舊內存空間。
?
那么無法復用舊內存空間,對應有程序與操作系統各有什么影響呢?小夕還沒有探索出嚴謹的結論,讀者有思路可以跟小夕一起討論哦~
?
如果倍率改為比2大的數,結果是一樣的。有興趣的喵喵可以自行畫畫圖~當然,數學好的喵喵不用畫圖也能證明出來的~(利用幾何級數的性質)
}
?
if(倍率<2&&倍率>1){
比如倍率采用1.5。小夕再畫一下圖~
?
可以看到,第三次擴容后的新數據結構大小約為338B!而舊空間的大小是250+225=475>338,也就是說新的哈希表可以挪到舊的內存空間了!內存得到了復用!
?
好咯,說到這里,讀者應該懂了,對于加倍式擴容,倍率必須小于2才能復用內存。那么為什么默認值取1.5,而不是1.6,1.7呢?小夕查了很多資料,發現這是一個啟發式策略(啟發式策略就是拍腦袋想出來的看似合理而沒有嚴謹理論依據的方法)。
?
一個疑問
?
那么既然看似倍率用1.5要優于2,為什么Java中的哈希表系列以及C++中的Vector卻采用2呢?
?
這就是理論與工程的不同之處。在工程中不僅要考慮內存復用這一個問題,還要考慮到浮點數運算問題和大量數據場景下的擴容速度的問題。
?
具體來說,若采用1.5倍,那么假設數據結構初始大小為10,則以后的數據結構大小會依次計算為:
15,
22.5,
33.75,
50.625,
75.9375
...
?
可以看到浮點運算的代價會越來越高。
?
擴容速度也很好理解。大量數據時,2倍擴容速度會比1.5倍擴容速度少很多次擴容次數,因此效率會比1.5倍高很多。那么當程序不怎么看重內存復用,卻有大量數據待填入數據結構時,2倍是更合理的。
?
So
雖然很多數據結構都是基于靜態數組實現的動態空間增長,但是有的是上述提到的2倍的擴容倍率,有的像Java中的ArrayList則為1.5倍的擴容倍率。
?
看來如何決定倍率,要在設計數據結構的時候好好考慮這個數據結構將來的業務場景呢。
PS:
沒有發現小夕在上面的一個if語句中漏了一半括號的C/C++/Java等程序員請自覺面壁思過。
?
最后,不知道您對小夕的文章是否滿意呢(?????????)
小夕已委托維權騎士對小夕發布文章的版權行為進行追究與維權。歡迎大家轉發分享~如需轉載,請聯系微信xiyaomengmengda。?
總結
以上是生活随笔為你收集整理的小夕说,不了解动态空间增长的程序喵都是假喵(下)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android自定义Lint实践
- 下一篇: 基本功 | Litho的使用及原理剖析