分攤分析[1]給我的印象是大概是心理安慰,讓我們放心的用,而不去擔心會有什麼壞的效能問題。比如c++ 的vector 動態增長,每個操作的分攤時間複雜度是o(3)。
有三種操作手法:
聚類方法
最壞情形下,一系列操作總的代價上界除以操作個數,就是每個操作的分攤代價。
這裡每個操作的分攤代價相同。
例子 二進位制計數器
inc(a)
i = 0
while i < a.length and a[i] == 1
a[i] = 0
i = i + 1
if i < a.length
a[i] = 1
初始時a[0..k] = 0.
inc(a)最壞是o(k), n次inc最壞達到o(nk)。
但是我們注意不是每次都o(k),只是全一時才這樣。
我們來數字元位翻轉的次數。第0位翻轉了n次,
第1位翻轉了n/2次,總共< 2n。每個inc的分攤代價是o(2)。
記賬方法
每種操作型別分攤代價可能不同,高於實際代價的差值稱為prepaid credit。
例子 push,pop,multipop(k)的實際代價分別是1,1,min(k,s),
而賦予分攤代價分別為2,0,0。當push時,消耗1,剩餘的1存入該物件,當pop時,
使用該物件上存入的1。
勢能方法
把credit當成整個資料結構的勢能,而不是單個樹據物件的。
例1 紅黑樹重建的代價
rb_insert/rb_delete 首先需要o(lgn)查詢到key所在節點,然後只分別需要o(1)的節點插入,節點刪除和旋轉,但是改變顏色
最壞可能是lgn, 其他可能是多次,或零次。
定義勢能函式phi(t)=sum, 其中如果x是紅色,或者x是黑有兩個紅孩子,則w(x)=0; 如果x是黑,沒有紅孩子,則w(x)=1; 如果x是黑,有兩個紅孩子,則w(x)=2。
證明:任一rb_insert/rb_delete後,phi(t)至少減少一。從任意混合的插入刪除序列的分攤代價是o(1)。
例2 自組織鍊錶:
搜尋必須從煉表頭開始,如果在第k項找到,則代價為k。
搜尋後允許使用任何啟發式方法調整鍊錶順序。
heuristic knowing entire access sequence.雖然我不知道這種最優方法的代價,
但是我們使用勢能分析,即使預先不知道訪問序列,move-to-front heuristic方法的代價不超過最優方法代價的兩倍。
例3 伸展樹[2]
如果想要和紅黑樹一樣的分攤複雜度,而編碼複雜度不要那麼高,就用這個。
參考
[1] 演算法導論第三版
[2]
SQL資料分攤
場景 到季未公司按照部門貢獻率進行對各部門發放獎金,然後部門內部按效績優先順序分攤獎金 方案 參考網上資料,使用cte函式遞迴處理 if object id tempdb.emplbonus is not null drop table emplbonus create table emplbonu...
分攤 分配 定期重過賬
分攤是既分攤初級成本又分攤次級成本至co中物件的方法。成本分攤的規則可以有很多,比如根據統計指標,根據百分比,根據權重,根據固定金額等等。我們在系統中將分攤規則定義在乙個重要的引數 分攤迴圈中。分攤迴圈是多行的。每一行中都定義了分攤成本流的傳送方,接受方,分攤規則等內容。在月末我們指定需要執行的迴圈...
資料結構 向量的擴充(分攤複雜度分析)
在原本的向量中,由於採用靜態空間管理策略 開闢內部陣列 elem並使用一段連續的物理空間 capacity 總容量 size 當前實際規模 這個管理策略顯然存在不足,會發生上溢或者下溢 1 上溢 overflow elem不足以存放所有元素 2 下溢 underflow elem中元素寥寥無幾 裝填...