Set
要素を挿入するためにa の完全なコピーを作成する必要はありません。内部的には、要素はツリーに格納されます。つまり、挿入のパスに沿って新しいノードを作成するだけで済みます。手つかずのノードは、 の挿入前バージョンと挿入後バージョンの間で共有できますSet
。そして、Deitrich Eppが指摘したように、バランスの取れたツリーO(log(n))
では、挿入のパスの長さです。(肝心なところが抜けててすいません。)
タイプTree
が次のようになっているとします。
data Tree a = Node a (Tree a) (Tree a)
| Leaf
...そしてTree
、次のようながあるとします
let t = Node 10 tl (Node 15 Leaf tr')
... ここでtl
とtr'
は、いくつかの名前付きサブツリーです。12
ここで、このツリーに挿入したいとします。さて、それは次のようになります。
let t' = Node 10 tl (Node 15 (Node 12 Leaf Leaf) tr')
サブツリーtl
とtr'
は と の間で共有されてt
おり、 のサイズが 3 よりもはるかに大きくなる場合でも、t'
3 つの新しいサブツリーを作成するだけで済みます。Nodes
t
編集:リバランス
リバランスに関しては、次のように考えてください。空のツリーがあるとします。すでにバランスが取れています!ここで、要素を挿入するとします。すでにバランスが取れています!ここで、別の要素を挿入するとします。まあ、奇数があるので、そこでは大したことはできません。
ここがトリッキーな部分です。別の要素を挿入するとします。これには、左または右の 2 つの方法があります。バランスかアンバランスか。バランスが取れていない場合は、ツリーの回転を明確に実行してバランスを取ることができます。バランスが取れている場合は、すでにバランスが取れています。
ここで注意すべき重要なことは、常にリバランスを行っているということです。要素を挿入することを決定したツリーがごちゃごちゃしているわけではありませんが、その前にバランスを取り直し、挿入が完了した後に混乱を残します。
ここで、要素を挿入し続けるとします。木はバランスを崩しますが、それほどではありません。そして、それが起こった場合、最初にそれをすぐに修正し、次に修正はO(log(n))
バランスの取れたツリーにある挿入のパスに沿って発生します。リンク先の論文の回転は、回転を実行するためにツリー内の最大 3 つのノードに接触しています。O(3 * log(n))
そのため、リバランス時に作業を行っています。それはまだO(log(n))
です。