算法导论之平摊分析(动态表)
平攤分析,amortizedanalysis,對數據結構執行的所有操作的總和時間是油由求平均而得出,用來證明一系列操作中,通過對所有操作求平均代價,即時某一操作具有較大代價,但平均代價還是小的。導論中這個和平均情況分析不同,我自己到沒感覺出不同,同樣是求平均。Amortized,攤銷之意,就是將把總代價平均到一個周期內來承擔。
平攤分析有什么意義呢?主要為認識數據結構。對數據結構的一系列操作,數據結構并非總是靜態的,每一個操作都可能引發數據結構的改變,而影響下一步操作的執行代價,用總體來刻畫,可以為我們選擇怎樣的數據結構以及如何對數據結構執行操作提供性能上的量化判斷。
平攤分析有三種方法:聚集分析、記賬法、勢能法。
聚集分析,證明對所有的n個操作所構成的序列的總時間在最壞情況下為T(n)。在最壞情況下,每個操作的平均代價就是T(n)/n。總體最壞,平均下去就是每個操作的最壞情況。
記賬法,則是通過對操作賦予價值,價值儲蓄用于后續支出。如果一個操作的代價小于平攤代價,就是時間花費小,那么可以儲蓄起來,用于給那些代價大于平攤代價的操作。只要確保總儲蓄最后大于等于零,那么平攤就成立。
勢能方法,思路和記賬法一樣,對數據結構的每一個操作用能或勢來表示,也就是先存起能量,支付后面需要消耗能量的操作。需要定義一個勢函數。
通過二進制計數器累進來說明這三類方法。K位二進制計數器,用A[0..k-1]表示,位數長度為k,最低位在A[0],最高位在A[k-1]中。計數器加1的函數如下:
Fun_Increment(A){
??? i=0;
??? while i<length(A) and A[i]=1
??????? do A[i]=0;//該位是1,加1就累進一位
?????????? i=i+1;
??? if?i<length(A) //該位是0,那就直接加1,不累進
??????? then A[i]=1;
}
分析該函數最壞情況下的執行次數,數組中位數全是1,那么就要執行循環位數長度k次,那么要執行n次加1操作,就要O(nk)代價,這是最壞情況下。但這個大致分析,明眼就能看出雖然正確,但不夠精確。深入下,把0和1的累進看做翻牌,實際上每一位都是前一位的1/2翻牌,就是隔一次才會翻牌。用初始位0來說明,n次操作,A[0]要翻牌n次,但A[1]只要翻牌1/2次,同樣依次往高位去,都是呈1/2來翻牌的次數。可得:
如此,總代價是O(n),平攤代價就是O(1)。
利用平攤分析,證明表的插入和刪除操作平攤代價為O(1),以研究表的動態擴展和壓縮。用表的裝載因子作為表壓縮和擴張的標志,裝載因子是表中存儲元素個數除以表大小的結果。當裝載因子等于1時,表滿,則擴展原表的兩倍,使新表的裝載因子為1/2;當裝載因子小于1/2時,壓縮原表一半。表插入和刪除的操作次數主要是插入和刪除本身1次動作,以及如果裝載因子超出界限,插入原表到新表的操作。動態表的擴展和壓縮可以按照以上方法求得平攤分析結果。動態表的函數和平攤分析就不多敘述,在算法思想上并無可書寫之處,倒是平攤分析的意義要在最后再理解一次。
平攤分析作為算法性能分析的方法,其目的在平均操作的代價來評估算法的應用價值。從整體上考慮其性能代價,忽略部分操作的高消耗,從而得出更精確的算法開銷。針對數據結構的每一次操作都帶來結構的變化,換句話說,這一系列對數據結構的操作不是獨立,是互相關聯,這樣每次操作的代價不應該由獨立的該次操作來承擔開銷,而應該是所有操作來承擔。從操作的因果關系來說,以二進制計數器為例,前一次操作的復位個數決定后一次操作的復位個數,這樣的關系就是平攤分析的價值所在。因為這個操作序列中各個操作可能會是相互制約的,所以開銷很大的那些個個操作,在操作序列總開銷中的貢獻也應該被平衡和分擔。
平攤分析的輸入是問題的具體條件以及若干個相互關聯的操作序列,輸出是在該問題的條件下,這個動作序列的每一個動作(不管動作的執行內容)的平攤性能開銷并不等于最大開銷動作的最壞時間,而是平均開銷代價。如果我們設計了一個數據結構,然后施以一系列操作,通過總體平攤開銷來反映其性能,比用某一個具體操作的最壞代價來考量更有意義。可以通俗地說:平均身高更能反映一個地區的水平,而不是通過最高和最低部分。總結
以上是生活随笔為你收集整理的算法导论之平摊分析(动态表)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MapReduce基础开发之八HDFS文
- 下一篇: MapReduce基础开发之九JDBC连