三叉树?
编辑 2:在您查看了您的问题后,您似乎仍不清楚您希望在搜索时如何浏览此三叉树。一棵二叉搜索树根据哪个更大将其元素左右划分。你没有描述过类似的标准:你的函数什么时候应该使用第一个、第二个和第三个分支?
编辑 3:我已经提供了适用于三叉树的函数 pathExists,但仍然缺少 AddNode,因为您没有对我用粗体突出显示的问题提供任何见解。如果您的树确实用于在 3 维空间中包含点,那么它确实听起来像您想要一个 k-d 树,正如我曾经建议的那样。我还部分提供了函数make3DTree,假设你正在寻找一个k-d树。
直到我看到你用ternary tree(或者一般是n-ary tree)绘制的图,我才明白你的问题。一棵三叉树在每一层只有(最多)三个子节点,而不是二叉树的两个。
“树中的树中的树”的措辞与branching factor (2, 3, n) 不同。究竟如何将三元组 (25, 7, 11)、(25, 7, 22)、(25, 10, 4) 和 (30, 7, 22) 转换为 your ternary tree 对我来说仍然有点令人费解。似乎底部节点只有两个空叶子。我将其解释为中间有第三个空箭头。
您的AddNode 函数构造binary search trees,其中较小的元素位于左侧,较大的元素位于右侧。 但是,您希望如何使用第三个分支?
比较以下通用/特定于整数的二叉树数据类型定义,
datatype 'a btree = BTreeEmpty | BTreeNode of 'a * 'a btree * 'a btree
datatype int_btree = BTreeEmpty | BtreeNode of 'a * int_btree * int_btree
与三叉树的那些,
datatype 'a ttree = TTreeEmpty | TTreeNode of 'a * 'a ttree * 'a ttree * 'a ttree
datatype int_ttree = TTreeEmpty | TtreeNode of 'a * int_ttree * int_ttree * int_ttree
甚至是在每个节点中支持变量分支的那些,
datatype 'a tree = TreeEmpty | TreeNode of 'a * 'a tree list
datatype int_tree = TreeEmpty | TreeNode of int * int_tree list
创建您描绘的三叉树,
val treeModel =
let val t = TTreeNode
val e = TTreeEmpty
in
t (25,
e,
t (7,
e,
t (11, e, e, e),
t (10,
e,
t (4, e, e, e),
e
)
),
t (30,
e,
t (7,
e,
t (22, e, e, e),
e
),
e)
)
end
虽然使用AddNode 之类的函数可能会更方便,但您只需要指定一种一致的方式将元素添加到这种树中。 二叉搜索树逻辑如何转化为三叉树?
判断路径是否存在于三叉树中
您可以确定节点的路径是否存在。由于树可以有任意深度,因此路径可以有任意长度并且应该用列表来表示。例如,[25, 7, 10, 4] 存在路径 your ternary tree。
fun pathExists [] _ = true (* the empty path is trivially found *)
| pathExists _ TTreeEmpty = false (* no non-empty path goes through an empty tree *)
| pathExists (x::xs) (TTreeNode (y, subtree1, subtree2, subtree3)) =
x = y andalso
(pathExists xs subtree1 orelse
pathExists xs subtree2 orelse
pathExists xs subtree3)
用上面的treeModel测试这个函数:
- pathExists [25, 7, 10, 4] treeModel;
> val it = true : bool
- pathExists [25, 30, 7, 22] treeModel;
> val it = true : bool
- pathExists [25, 7, 11, 9] treeModel;
> val it = false : bool
- pathExists [25, 7, 9] treeModel;
> val it = false : bool
在三叉树中插入一个点 [???]
这个函数的模板可以是
fun AddNode (x, TTreeEmpty) = TTreeNode (x, TTreeEmpty, TTreeEmpty, TTreeEmpty)
| AddNode (x, TTreeNode (y, subtree1, subtree2, subtree3))) = ???
但是如果x <> y,它应该尝试将x添加到三个子树中的哪一个?
K-d 树?
编辑 1:回答后,我意识到您可能正在寻找一个k-d tree? k-d 树可以存储 k 维向量,仅使用二叉树,以一种允许有效的、特定于位置的查找的方式。
这里的大技巧是说树的第 1 层在 X 轴上将空间分成两半,树的第 2 层在 Y 轴上将左/右半部分分成两半,树的第 3 层在 Z 轴上将左/右半部分分成两半,在 X 轴上再次划分为第 4 层,在 Y 轴上再次划分为第 5 层,以此类推。
下面是 k = 3 的伪代码到标准 ML 的初始翻译:
(* 'byDimension dim (p1, p2)' determines if p1 is greater than p2 in dimension dim. *)
fun byDimension 0 ((x1,_,_), (x2,_,_)) = x1 > x2
| byDimension 1 ((_,y1,_), (_,y2,_)) = y1 > y2
| byDimension 2 ((_,_,z1), (_,_,z2)) = z1 > z2
| byDimension d _ _ = raise Fail ("Invalid dimension " ^ Int.toString d)
(* split points into two halves and isolate the middle element *)
fun splitAt dim points = ...
(* The number of dimensions, matching the arity of the point tuples below *)
val k = 3
fun make3DTree ([], _) = BTreeEmpty
| make3DTree (points, depth) =
let val axis = depth mod k
val len = List.length points
val points_sorted = ListMergeSort.sort (byDimension axis) points
val (points_left, median, points_right) = splitAt len points_sorted
in BTreeNode (median,
make3DTree (points_left, depth+1),
make3DTree (points_right, depth+1))
end
一种优化可能是减少不断的重新排序。
向这棵树添加单个 3D 点是明确定义的,但不能保证这棵树特别平衡:
(* get the (n mod 3)-th value of a 3-tuple. *)
fun getDimValue (n, (x,y,z)) =
let val m = n mod k
in if m = 0 then x else
if m = 1 then y else
if m = 2 then z else
raise Fail ("Invalid dimension " ^ Int.toString n)
end
(* the smallest tree that contains a k-dimensional point
* has depth k-1 (because of 0-indexing). *)
fun deepEnough depth = depth >= k-1
fun insertNode (point, BTreeEmpty, depth) =
let val v1 = getDimValue (depth, point)
val v2 = getDimValue (depth+1, point)
val (left, right) =
if deepEnough depth
then (BTreeEmpty, BTreeEmpty)
else if v1 > v2
then (insertNode (point, BTreeEmpty, depth+1), BTreeEmpty)
else (BTreeEmpty, insertNode (point, BTreeEmpty, depth+1))
in BTreeNode (v1, left, right)
end
| insertNode (point, BTreeNode (v1, left, right), depth) =
let val v2 = getDimValue (depth, point)
in if v1 > v2
then BTreeNode (v1, insertNode (point, left, depth+1), right)
else BTreeNode (v1, left, insertNode (point, right, depth+1))
end
可以通过执行最近邻搜索来确定这棵树中是否存在一个点,实现起来稍微不那么简单。