现在我有一个在SMLNJ中建模的二叉树,但我想将此模型更改为树内的树内有树的位置。(三元树)
如果从二叉树的根开始。
Binode with an (id1*(binode)) ß- a binary tree
然后,如果该“binode”位于元组的一部分:2Dbinode
该元组有一个标识符,而binode with是二进制树的根。
2Dbinode (id2* (binode) *2Dbinode)
其中每一个都是3Dbinode的一部分,包括:
3Dbinode(id3 * (2Dbinode) * 3Dbinode)
对于前。 3Dbinode(id3 *(2Dbinode)* 3Dbinode)根3Dbinode可能包含以下数据:
(25, (7, (11)))
And by adding the nodes (25, (7, (22)))
(25, (10, (4))), (30, (7, (22)))
这是我正在修改的2D二进制树的SMLNJ代码。
datatype btree = Empty | Node of int * btree * btree;
fun AddNode (i:int, Empty) = Node(i, Empty, Empty) |
AddNode(i:int, Node(j, left, right)) =
if i = j then Node(i, left, right)
else if i < j then Node(j, AddNode(i, left), right)
else Node(j, left, AddNode(i, right));
fun printInorder Empty = () |
printInorder (Node(i,left,right)) =
(printInorder left; print(Int.toString i ^ " "); printInorder right);
val x : btree = AddNode(50, Empty);
val x : btree = AddNode(75, x);
val x : btree = AddNode(25, x);
val x : btree = AddNode(72, x);
val x : btree = AddNode(20, x);
val x : btree = AddNode(100, x);
val x : btree = AddNode(3, x);
val x : btree = AddNode(36, x);
val x : btree = AddNode(17, x);
val x : btree = AddNode(87, x);
printInorder(x);
我需要用N个随机化(3Dnodes)填充数据结构:
如何实施这些功能?
搜索显示节点ex:(25,10,4)路径的特定节点
如果用户搜索不存在的节点: (30,(7,(30)))然后显示的路径是
如果用户希望在任何级别添加节点,则应提示他们输入该节点的3位数代码;应该再次显示路径。
以(A,B,C)的顺序打印出3dbinode树的内容 删除节点 删除节点:EX:DEL(30,7,_) 那么结果就是 - (30,7,22)删除 - (30,7,0)创建
答案 0 :(得分:1)
编辑2:在您查看了问题之后,您仍然不清楚在搜索时如何浏览此三元树。 二进制搜索树根据哪个更大的元素左右划分它们的元素。您没有描述类似的标准:您的函数何时应使用第一个,第二个和第三个分支?
编辑3:我提供了适用于三元树的函数pathExists
,但AddNode
仍然缺失,因为您没有对我突出显示的问题提供任何见解大胆的。如果您的树确实用于在三维空间中包含点的目的,那么 听起来就像您想要一个 k-d树,就像我建议的那样。我还假设你正在寻找一个k-d树,我也部分地提供了函数make3DTree
。
在我看到您使用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
添加到?{/ p>
编辑1:在回答之后,我意识到您可能正在寻找 k-d tree ? k-d树可以存储k维向量,仅使用二叉树,以允许有效的,特定于位置的查找。
这里的一个很棒的技巧是说树的第一层在X轴上将空间分成两半,树的第二层将左/右半部分成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
确定此树中是否存在一个点可以通过执行最近邻搜索来实现,这实现起来稍微不那么简单。