【问题标题】:How can I create a ternary tree in SMLNJ?如何在 SMLNJ 中创建三叉树?
【发布时间】:2016-06-20 20:21:00
【问题描述】:

现在我有一个在 SMLNJ 中建模的二叉树,但是我想将此模型更改为 tree inside of tree inside of tree。(三叉树)

如果你从二叉树的根开始。

    Binode with an (id1*(binode))  ß- a binary tree

那么如果那个“binode”作为一个元组的一部分:2Dbinode

那个元组有一个标识符,那个二元节点是二元节点树的根。

    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

这是我正在修改的二维二叉树的 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 个随机(3D 节点)填充数据结构:

如何实现这些功能?

搜索显示节点路径的特定节点 ex: (25, 10, 4) 显示将是

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

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

  • (25)
  • (30)
  • (30,7)
  • (30、7、30)未找到

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

  • EX: ADD (30, 11, 5) 那么显示会是
    • (25)
    • (30)
    • (30, 7)
    • (30, 11) 已创建
    • (30, 11, 5) 已创建

将 3dbnode 树的内容打印为 (A,B,C) 的序列 删除一个节点 删除节点:EX: DEL (30, 7, _) 那么结果将是 - (30, 7, 22) 已删除 - (30, 7, 0) 已创建

【问题讨论】:

  • 我已经调整了原来的问题。是的,你是对的,我正在寻找三叉树。

标签: sml smlnj


【解决方案1】:

三叉树?

编辑 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 &lt;&gt; 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

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

【讨论】:

  • 是的,每个节点应该有三个孩子:左、中、右。
  • 你回答得很少。
  • 对不起,我已经在上面的原始问题中详细说明了。我认为这将把它放在我正在努力完成的更好的背景下。
  • 是的,对不起,我的英语不太好。当我说 3d 树时,我指的是三元树。
猜你喜欢
  • 2015-05-21
  • 2010-10-24
  • 2015-01-14
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 2021-12-20
  • 2017-07-01
相关资源
最近更新 更多