"BinaryTree" (データ構造)
"BinaryTree"
各ノードに保存される値が一般式である可変二分木を表す.
詳細
- 二分木は,各ノードに関連付けられたデータに基づくノードを評価するためだけでなく,2つまでの枝との階層関係を表すためにも役立つ.
-
CreateDataStructure["BinaryTree",v] 指定された初期値 v を持ち,左と右に子を持たない新しい"BinaryTree"を作成する CreateDataStructure["BinaryTree",v{l,r}] 指定された初期値 v と指定された左と右の子を持つ新しい"BinaryTree"を作成する Typed[x,"BinaryTree"] x に"BinaryTree"型を与える - "BinaryTree"型のデータ構造については,以下の演算が使える.
-
ds["BreadthFirstScan",f] ds の幅優先探索を行い,各ノードのデータを f に渡す time: O(n) ds["Copy"] ds のコピーを返す time: O(n) ds["Data"] 木のノード ds に保存されたデータを返す time: O(1) ds["InOrderScan",f] ds の間順探索を行い,各ノードのデータを f に渡す time: O(n) ds["Left"] ds の左の子のデータ構造を返す time: O(1) ds["LeftNullQ"] ds の左の子が空値である場合にTrueを返す time: O(1) ds["NullQ"] ds が空値である場合にTrueを返す time: O(1) ds["PostOrderScan",f] ds の後順探索を行い,各ノードのデータを f に渡す time: O(n) ds["PreOrderScan",f] ds の前順探索を行い,各ノードのデータを f に渡す time: O(n) ds["Right"] ds の右の子のデータ構造を返す time: O(1) ds["RightNullQ"] ds の右の子が空値である場合にTrueを返す time: O(1) ds["SetData",v] 木のノード ds に保存されたデータを v に設定する time: O(1) ds["SetLeft",l] 木のノード ds の左の子を l に設定する time: O(1) ds["SetRight",r] 木のノード ds の右の子を r に設定する time: O(1) ds["ValidQ"] ds が有効な木である場合にTrueを返す time: O(n) ds["Visualization"] ds の可視化を返す time: O(n) - 以下の関数もサポートする.
-
dsi===dsj dsi が dsj に等しい場合はTrue FullForm[ds] ds の完全形 Information[ds] ds についての情報 InputForm[ds] ds の入力形 Normal[ds] ds を通常の式に変換する
例題
すべて開く すべて閉じる例 (2)
新しい"BinaryTree"は,CreateDataStructureを使って作成できる:
ds = CreateDataStructure["BinaryTree", 10]ds["Data"]ds["SetData", 12]ds["Data"]ds["LeftNullQ"]ds["RightNullQ"]指定された子を持つ新しい"BinaryTree"を作成する:
ds = CreateDataStructure["BinaryTree", 1 -> {2 -> {5, Null}, 8}]ds["LeftNullQ"]ds["Left"]Normal[ds]ds["Visualization"]スコープ (1)
情報 (1)
新しい"BinaryTree"は,CreateDataStructureを使って作成することができる:
ds = CreateDataStructure["BinaryTree", f[1]]Information[ds]アプリケーション (7)
二分探索木 (1)
二分木は,順序付けられたものをソートするのに使われる.通常これらは二分探索木と呼ばれる.以下は,簡単な挿入プログラムである:
insert[node_, d_] :=
With[{curr = node["Data"]},
Which[
d < curr,
If[node["LeftNullQ"], node["SetLeft", CreateDataStructure["BinaryTree", d]], insert[node["Left"], d]]
,
d > curr,
If[node["RightNullQ"], node["SetRight", CreateDataStructure["BinaryTree", d]], insert[node["Right"], d]]
]
]ds = CreateDataStructure["BinaryTree", 50];
Scan[insert[ds, #]&, RandomInteger[{0, 500}, 30]];ds["Visualization"]二分木に対して間順探索を行う.ソートされているので,この例で示されるように,要素はソートされた順に訪れられる:
arr = CreateDataStructure["DynamicArray"];ds["InOrderScan", arr["Append", #]&];
arr//Normalこのような基本の二分探索木の問題は,挿入鎖が非平衡になり,木の最大深さが大きくなる可能性がある点である.この問題は,さまざまな形式の平衡二分木によって修正される.
木の回転 (1)
ソートされた二分木の回転演算には,要素の順序を維持しながら木構造を変更させることが必要である.回転演算は,平衡二分木を作成する数多くの方法によって使用される.
RightRotate[y_] :=
Module[{x, tmp},
x = y["Left"];
tmp = x["Right"];
x["SetRight", y];
y["SetLeft", tmp];
x]LeftRotate[x_] :=
Module[{y, tmp},
y = x["Right"];
tmp = y["Left"];
y["SetLeft", x];
x["SetRight", tmp];
y]ここでは二分木が作成される.左に2つのレベルのノードがあり,右には何もない.これは非効率的なストレージである:
ds = CreateDataStructure["BinaryTree", 3 -> {1 -> {0, Null}, Null}];
ds["Visualization"]右回転は,ソートされた特性を維持しつつ,ノードを右に移動させ,より平衡の取れた木にする:
ds = RightRotate[ds];
ds["Visualization"]ds = LeftRotate[ds];
ds["Visualization"]ランダムな木 (1)
InsertRandom[node_, lim_] :=
Module[ {test, newNode},
test = RandomChoice[ {Left, Right, All}];
If[ (test === Left || test === All) && lim ≥ 0,
newNode = CreateDataStructure["BinaryTree", 1];
node["SetLeft", newNode];
InsertRandom[newNode, lim - 1]];
If[(test === Right || test === All) && lim ≥ 0,
newNode = CreateDataStructure["BinaryTree", 1];
node["SetRight", newNode];
InsertRandom[newNode, lim - 1]];
node
]ds = InsertRandom[CreateDataStructure["BinaryTree", 1], 4]ds["Visualization"]二分木の最大の深さを計算する (1)
二分木の最大の深さは,根のノードから葉のノードまでの最長経路に沿ったノードの数である.
MaximumDepth[tree_] :=
If[tree["NullQ"],
0,
Max[MaximumDepth[tree["Left"]], MaximumDepth[tree["Right"]]] + 1
]tree = CreateDataStructure["BinaryTree", 1 -> {2 -> {5 -> {7 -> {8, Null}, Null}, Null}, 2 -> {Null, 5}}];
tree["Visualization"]MaximumDepth[tree]最下位共通先祖を求める (1)
木における2つのノードの最下位共通先祖は,両方のノードを子孫として持つ最下位(最も深い)ノードである.これは,簡単なコードで計算できる.
木にランダムなノードを挿入するプログラム.これは,すべてのノードが他と区別できるものであることを確かめるためにカウンタを使う:
InsertRandom[node_, cnt_, lim_] :=
Module[ {test, newNode},
test = RandomChoice[ {Left, Right, All}];
If[ (test === Left || test === All) && lim ≥ 0,
newNode = CreateDataStructure["BinaryTree", cnt["Increment"]];
node["SetLeft", newNode];
InsertRandom[newNode, cnt, lim - 1]];
If[(test === Right || test === All) && lim ≥ 0,
newNode = CreateDataStructure["BinaryTree", cnt["Increment"]];
node["SetRight", newNode];
InsertRandom[newNode, cnt, lim - 1]];
node
]SeedRandom[ 14]tree = InsertRandom[CreateDataStructure["BinaryTree", 0], CreateDataStructure["Counter", 1], 7];
tree["Visualization"]LowestCommonAncestor[tree_, left_Integer, right_Integer] :=
Which[
tree["NullQ"], tree,
tree["Data"] === left, tree,
tree["Data"] === right, tree,
True,
Module[{sleft, sright},
sleft = LowestCommonAncestor[tree["Left"], left, right];
sright = LowestCommonAncestor[tree["Right"], left, right];
Which[
sleft["NullQ"], sright,
sright["NullQ"], sleft,
True, tree
]
]
]LowestCommonAncestor[tree, 15, 20]["Data"]LowestCommonAncestor[tree, 15, 20]["Visualization"]二分木が対称であるかどうかを検証する (1)
二分木が対称であるかどうかを検証するプログラム.これは,データが等しく,左と右のノードが対称であることをチェックする:
SymmetricTreeQ[tree_] :=
SymmetricTreeQ[tree["Left"], tree["Right"]]
SymmetricTreeQ[x_, y_] :=
Which[
x["NullQ"] && y["NullQ"],
True,
x["NullQ"] || y["NullQ"],
False,
True,
x["Data"] == y["Data"] && SymmetricTreeQ[x["Left"], y["Right"]] && SymmetricTreeQ[x["Right"], y["Left"]]
]tree = CreateDataStructure["BinaryTree", 1 -> {2 -> {5, Null}, 8}];tree["Visualization"]SymmetricTreeQ[tree]tree = CreateDataStructure["BinaryTree", 1 -> {2 -> {5, Null}, 2 -> {Null, 5}}];
tree["Visualization"]SymmetricTreeQ[tree]二分木の直径を求める (1)
二分木の直径は,任意の2つのノード間の最長経路(根を通る場合も通らない場合もある)の長さである.
BinaryTreeDiameter[tree_] :=
Module[{diameter},
diameter = CreateDataStructure["Value", 1];
BinaryTreeDepth[diameter, tree];
diameter["Get"] - 1
]
BinaryTreeDepth[diameter_, tree_] :=
Module[{left, right},
If[tree["NullQ"], Return[0]];
left = BinaryTreeDepth[diameter, tree["Left"]];
right = BinaryTreeDepth[diameter, tree["Right"]];
diameter["Set", Max[diameter["Get"], left + right + 1]];
Max[left, right] + 1
]tree = CreateDataStructure["BinaryTree", 1 -> {2 -> {5, Null}, 2 -> {Null, 5}}];
tree["Visualization"]BinaryTreeDiameter[tree]tree = CreateDataStructure["BinaryTree", 1 -> {2 -> {5 -> {7 -> {8, Null}, Null}, Null}, 2 -> {Null, 5}}];
tree["Visualization"]BinaryTreeDiameter[tree]考えられる問題 (2)
空ノード (1)
ds = CreateDataStructure["BinaryTree", 10]rChild = ds["Right"]rChild["NullQ"]空ノードの内容に対して作用する演算を行うとエラーが発生する:
rChild["Data"]空ノードのシリアライゼーションはNullである:
InputForm[ rChild]DataStructure["BinaryTree", {"Data" -> Null}]CreateDataStructureで空ノードを作成する:
CreateDataStructure["BinaryTree", Null]["NullQ"]CreateDataStructure["BinaryTree"]["NullQ"]Wolfram言語における空ノードの表現は,ノードが空であるかどうかをチェックしなくても,二分木のノードを操作するアルゴリズムを書くことが可能となるので,大変便利である.
有効な木 (1)
Wolfram言語の二分木のインターフェースは,柔軟かつ効率的であるように設計されている.このことによって,作成した構造に何らかの影響があることもある.
ds = CreateDataStructure["BinaryTree", 10]ds1 = CreateDataStructure["BinaryTree", 20];
ds["SetRight", ds1];
ds["Visualization"]ds1["SetRight", ds];結果としてできたものは木ではない.このことは,"ValidQ"演算を使って確かめることができる:
ds["ValidQ"]演算によっては,木が有効でない場合にエラーを発することもある:
ds//Normal無効な構造が作成された場合に挿入関数がエラーを発しないということは,それらの関数があまり効率的ではないということである.データ構造をシリアライズするこのような演算には,組込みのチェックが含まれている.
関連するガイド
-
▪
- データ構造 ▪
- コンパイルの型 ▪
- コードのコンパイル ▪
- グラフとネットワーク
履歴
2020 で導入 (12.1)