替罪羊樹 知識總結

2022-10-10 11:33:12 字數 1594 閱讀 3191

替罪羊樹是一類神奇的平衡樹。它最神奇的地方就在於,大部分平衡樹都是用愚蠢的單旋來維護平衡,而fhq-treap則是用split和merge維護平衡的,可替罪羊樹卻是用一種神奇的操作維護平衡的,那就是重構rebuild。每次插入和刪除元素的時候,檢查子樹大小,若失衡則直接重購以維護整棵樹平衡。

在講思路前,我們先要注意乙個點:替罪羊樹僅能用重構來維持平衡,因而若節點被刪除後,無法將其高效的移除,所以我們採取懶惰刪除,每次僅將節點的計數器--即可。

先來看一下我們的變數區和基礎的函式吧:

struct node;

inline void update(int p)

接下來我們來看看重構操作吧。我們預先設定乙個閾值α,一般取[0.7,0.8]左右,若檢查到某個節點的兒子所在子樹的sz佔這個節點sz的比例超過α時,就重構。由於當被刪除節點過多時,搜尋樹效率也會顯著降低,於是當乙個節點的sd佔其sz的比例超過α時,亦重構。
inline bool can_rbu(int p)

那麼怎麼重構呢?我們已經知道了,對於一棵平衡樹,它的中序遍歷是排好序的。所以我們把它的中序遍歷拉到陣列中,然後重新二分建樹即可:
int tmp[100010];

void rbu_flatten(int &num,int p)

int rbu_build(int l,int r)

void rbu(int &p)

以上就是基本函式啦!其餘的部分神似普通的平衡樹,我們的介紹和注釋就稍微簡略一些了咯。

首先是插入和刪除。我們在遍歷路徑上每乙個節點時,都檢查是否滿足重構條件,並重構即可。其餘與普通二叉搜尋時雷同。

void insert(int &p,int val)

else

最後是查詢前後驅的函式。在此我們稍微的改變一下函式的返回值:將返回數值改為返回下標。這樣以後查詢排名就可以用前驅座標+1即可。**依舊與普通平衡樹相同……
int get_uprb(int p,int val)

while (isdigit(ch))

x *= f;

return;

}template void write(t x)

if(x > 9)

write(x/10);

putchar(x % 10 + '0');

return;

}int n;

int rt,tot=0;

struct nodef[100010];

const double alpha=0.75;

inline void update(int p)

inline bool can_rbu(int p)

int tmp[100010];

void rbu_flatten(int &num,int p)

int rbu_build(int l,int r)

void rbu(int &p)

void insert(int &p,int val)

else

int main()

} return 0;

}

替罪羊樹SCT

照著指標版的打了個陣列版的,發現自己上了一節c 語法課。重構什麼的,最難在於找出深度最小的需要重構的節點,畢竟多寫乙個函式不太優雅,陣列又不像指標那麼方便直接修改。如果你要傳回乙個變數的位址 因為你直接修改這個位址ch等等就直接跟著改了,十分方便 函式不能寫 int 得寫int 刪除還是不要重構,太...

總結 替罪羊樹學習筆記

突然不會寫學習筆記了.反正是給自己看的 那就想到哪寫到哪吧 不基於旋轉而基於暴力重構的平衡樹 採用懶惰刪除法 每次刪除只打標記,在重構時統一刪除 如果某個點的子樹過於不平衡或刪除了過多的元素 那就需要進行重構 重構時暴力dfs整棵子樹,碰見打了刪除標記的節點就扔進記憶體池,否則按照中序遍歷存下來,然...

平衡樹 替罪羊樹

yangkai 身為平衡樹卻不做任何形式的旋轉,替罪羊樹可以稱得上是最暴力的平衡樹了。替罪羊樹 sgt 保留有二叉搜尋樹的基本性質,即對於任意乙個節點t,左兒子的所有節點比它小,右兒子的所有節點比它大。但是既然不基於翻轉,它怎樣維護平衡樹的優秀複雜度呢?sdt基於乙個叫做 重構 的操作,聽起來很是優...