如何在SMLNJ中创建三元树?

时间:2016-06-18 22:40:04

标签: sml smlnj

现在我有一个在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)))

3DBinary Tree Model

这是我正在修改的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)路径的特定节点

  • (25)
  • (25,7)
  • (25,10)
  • (25,10,4)

如果用户搜索不存在的节点: (30,(7,(30)))然后显示的路径是

  • (25)
  • (30)
  • (30,7)
  • (30,7,30)NOT FOUND

如果用户希望在任何级别添加节点,则应提示他们输入该节点的3位数代码;应该再次显示路径。

  • EX:ADD(30,11,5)然后显示
    • (25)
    • (30)
    • (30,7)
    • (30,11)创建
    • (30,11,5)创建

以(A,B,C)的顺序打印出3dbinode树的内容 删除节点 删除节点:EX:DEL(30,7,_) 那么结果就是   - (30,7,22)删除   - (30,7,0)创建

1 个答案:

答案 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>

K-d树?

编辑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

确定此树中是否存在一个点可以通过执行最近邻搜索来实现,这实现起来稍微不那么简单。