プログラミング
 Computer >> コンピューター >  >> プログラミング >> プログラミング

スプレー木(Splay Tree)とは?データ構造の特徴と回転操作をわかりやすく解説

スプレー木(splay tree)は、自己平衡型二分探索木の一種であり、「最近アクセスした要素には再び素早くアクセスできる」という特別な性質を持つデータ構造です。挿入・検索・削除といった基本操作は、ならし計算量 O(log n) で実行できます。

スプレー木の大きな特徴は、ランダムでない一連の操作に対して、そのパターンが事前に分からない場合でも、他の探索木よりも優れた性能を発揮することが多い点です。二分探索木における通常の操作はすべて、「スプレーイング(splaying)」と呼ばれる一つの基本操作と組み合わせて実行されます。

スプレー木の基本的な性質

各ノード a には、実数値のキー key(a) が格納されているものと仮定します。

任意の二分探索木において、ノード a の左部分木には key(a) よりも小さいキー値を持つ要素が含まれ、右部分木には key(a) よりも大きいキー値を持つ要素が含まれます。この規則により、探索効率が保たれています。

スプレー木における検索と回転操作

スプレー木では、まず通常の二分探索木と同じ手順で目的の要素 a を検索します。具体的には以下の流れです。

  • 根の値とクエリ要素を比較する
  • 小さければ左部分木を再帰的に探索する
  • 大きければ右部分木を再帰的に探索する
  • 等しければ検索完了

検索後、大まかに言えば、a の連続する祖先のペア(b = parent(a)、c = parent(b))ごとに、特定の組み合わせの回転操作を実行します。これらの回転の結果として、a が c の位置へ移動することになります。

zig 操作

a が奇数個の真の祖先を持つ場合、残りの祖先(根の子であるノード)も別途処理する必要があります。この終端ケースでは、a と根との間の辺を回転します。このステップは「zig 操作」と呼ばれます。

zig-zig 操作

a と b がどちらもそれぞれの親に対して同じ側の子(両方とも左子、または両方とも右子)である場合、まず b とその親 c の間の辺を回転し、次に a とその親 b の間の辺を回転します。このステップは「zig-zig 操作」と呼ばれます。

zig-zag 操作

a が左子(または右子)であり、b が反対側の右子(または左子)である場合、まず a と b の間の辺を回転し、次に a と c の間の辺を回転します。このステップは「zig-zag 操作」と呼ばれます。


  1. データ構造の範囲ツリー(レンジツリー)とは?仕組み・kd-treeとの違い・構築方法を解説

    範囲ツリー(range tree)は、点の集合を格納するための順序付き木構造として定義されるデータ構造です。最大の特徴は、指定された範囲内に存在するすべての点を効率的に取得できる点にあり、実務では主に2次元以上の空間で実装されます。範囲ツリーはkd-tree(kd木)とよく似た構造を持っていますが、両者には明確なトレードオフがあります。範囲ツリーはクエリ時間が O(logd n + k) とkd-treeより高速である一方、必要な記憶領域は O(n logd-1 n) と大きくなります。ここで、d は空間の次元数、n は木に格納されている点の総数、k は1回のクエリで取得される点の数を表します

  2. データ構造:仮想木におけるスプレー操作のアルゴリズム

    仮想木(Virtual Tree)では、一部の辺は実線(solid)として扱われ、その他の辺は破線(dashed)として扱われます。通常のスプレー操作は、実線で構成される木(solid tree)の内部でのみ実行されます。仮想木内のノード y でスプレーを行うには、以下に示す手法が用いられます。 このアルゴリズムは、木を3回走査し(各パスで1回ずつ)、その都度木を書き換えていきます。第1パスでは、ノード y から開始して実線の木内でのみスプレーを行うことで、y から木全体の根までの経路が破線に変わります。続いて、スプライシング(splicing)によってこの経路を実線に変換します。最後にノード