読者です 読者をやめる 読者になる 読者になる

RBST(Randomize Binary Search Tree)の計算量について考えてみた

RBSTは万能かつ簡潔な平衡二分木として有名ですね


Q.でもこれって計算量どうなんやろ
A.なんかいい感じやねん

のままだとよくないかなぁと思ってちょっと考えてみました

注意点として今回の記事では全部i番目というのは0-indexedです
あと、スピリチュアルです

"RBST木"を以下の感じで定義します

  • 根がi番目の可能性はそれぞれ1/(木のサイズ)
  • 左右の子はそれぞれRBST木

例えばサイズ7のRBST木の根を考えると
0と1と2と3と4と5と6がそれぞれ透明度1/7で重ね合わさってる感じ

そのなかで根が4の木をとりだして、根の左の子の根を見てみると0と1と2と3が透明度1/28で重ね合わさってる

Q.RBST木の高さの平均値的なのはO(logN)なの?
A.問題 J : 乱択平衡分二分探索木

まあこれはTreapだけど多少はね?(僕はこの問題を解いていません)

RBST木の高さの平均値的なのがO(logN)ならば、RBST木をmerge/splitした時にRBST木になることが示せればいい感じになるはず

merge

Node* merge(Node* l, Node* r) {
    if (!l->sz) return r;
    if (!r->sz) return l;
    if (xor128() % (l->sz + r->sz) < l->sz) {
        l->r = merge(l->r, r);
        return l->update();
    } else {
        r->l = merge(l, r->l);
        return r->update();
    }
}

この関数について、"lとrがRBST木なら, 返り値もRBST木である"ことを示せばいい。

xor128() % (l->sz + r->sz) < l->sz と、lとrがRBST木であることから、返り値の根は全部等確率

ここで、l->r = merge(l->r, r)に注目するとl->rとrは当然両方RBST木だから返り値もRBST木

l->lもRBST木だから結局lはRBST木

逆も然り

split

pair<Node*, Node*> split(Node* x, int k) {
    assert(0 <= k && k <= x->sz);
    if (!x->sz) return {last, last};
    if (k <= x->l->sz) {
        auto y = split(x->l, k);
        x->l = y.second;
        y.second = x->update();
        return y;
    } else {
        auto y = split(x->r, k- x->l->sz -1);
        x->r = y.first;
        y.first = x->update();
        return y;
    }
}

これについて、"xがRBST木なら返り値は両方RBST木"ということを示す ただしk

if (!x->sz) return {last, last}はどうでもいい

if (k <= x->l->sz) が真になった場合

auto y = split(x->l, k) だが, x->lがRBST木ゆえyは両方RBST木
よって返り値の左側は当然RBST木

右側の根は, xがRBST木ゆえk番目~(xのサイズ-1)番目で等確率
ゆえ右側もRBST木

偽になった場合->同様

ところで

RBSTのTってTreeだからRBST木ってヤバい