在标准ML中查找BST中节点的祖先

时间:2014-06-11 12:49:06

标签: binary-search-tree sml smlnj

我正在尝试在SML中找到BST中节点的父节点和祖父节点。

我试图修改此功能:

fun search(tree : bst, compare, (data) = 
    let fun s(Leaf) = NONE
          | s(Node{data=nodedata,left=left,right=right}) = 
                (case compare(data,nodedata) of
                      LESS    => s(left)
                    | GREATER => s(right)
                    | EQUAL   => SOME (Node{data=nodedata,left=left,right=right}))
     in
         s(tree)
     end 

通过改变输入,比较和输出的格式:

fun search(tree : bst, compare, (data) = 
 let fun s(Leaf) = NONE   
 |s(Node{data=nodedata,left=Node{data=nodedata1,left=left1,right=right1},right=right}) =                          
       (case compare(data,nodedata) of
           LESS    => s(left)
           | GREATER => s(right)
           | EQUAL   => SOME nodedata)

显然它不起作用,我想有一种更简单的方法可以做到这一点。

我添加了一个新变量,以便保存我正在检查的每个节点的当前父节点,并且它可以工作,但是(对我来说)很难找到一种方法来保持我检查的节点的祖父。

有什么想法吗?提前谢谢。

2 个答案:

答案 0 :(得分:1)

首先,你的搜索功能无法正常工作,所以我把它清理了一下。为了避免类型声明错误中的未绑定类型变量,您必须将bst类型定义为'a bst。我还修复了一个paranthesis错误。这是我的search函数的版本:

datatype 'a bst = Leaf | Node of {data: 'a, left: 'a bst, right: 'a bst}

(*search(tree, compare, key) = t
    where t = the tree which has `key` as its root
  *)
fun search(tree : 'a bst, compare : ('a * 'a -> order), key : 'a)
          : 'a bst option = 
  let 
    fun s(tree: 'a bst) : 'a bst option =
      case tree of
        Leaf => NONE
      | Node({data=x, left=l, right=r}) =>
          case compare(key,x) of
            LESS    => s(l)
          | GREATER => s(r)
          | EQUAL   => SOME tree
   in
       s(tree)
   end
(*Example:
search(Node({data=5,
             left=Node({data=3,
                        left=Node({data=2,left=Leaf,right=Leaf}),
                        right=Node({data=4,left=Leaf,right=Leaf})}),
             right=Leaf}),
       Int.compare,
       3);
*)

由于您需要一个返回搜索的父节点和祖父节点的函数,因此您需要一个返回以下元组的函数:(搜索节点,搜索节点的父节点,搜索节点的祖父节点)。但是,您不会总是有父母或祖父母。例如,如果您要查找的密钥已经位于主树的根目录中,则您将不会拥有父级或祖父级。因此,您需要使用option类型。如果没有用于该搜索的父节点,这将帮助您将NONE作为父节点返回。现在,您需要做的就是使用(您的主树,NONENONE)开始搜索,然后在沿树移动时,将父节点向右移动。如果找不到密钥,只需返回NONE的三元组。这是代码:

(*searchParent(tree, compare, key) =
    (t, the parent of t, the grandparent of t)
    where t = the tree which has `key` as its root
  *)
fun searchParent(tree : 'a bst, compare : ('a * 'a -> order), key : 'a)
                : ('a bst option * 'a bst option * 'a bst option) = 
  let 
    fun s(tree: 'a bst, par: 'a bst option, gpar: 'a bst option)
         : ('a bst option * 'a bst option * 'a bst option) =
      case tree of
        Leaf => (NONE, NONE, NONE)
      | Node({data=x, left=l, right=r}) =>
          case compare(key,x) of
            LESS    => s(l, SOME tree, par)
          | GREATER => s(r, SOME tree, par)
          | EQUAL   => (SOME tree, par, gpar)
   in
       s(tree, NONE, NONE)
   end

(*Example:
searchParent(Node({data=5,
             left=Node({data=3,
                        left=Node({data=2,left=Leaf,right=Leaf}),
                        right=Node({data=4,left=Leaf,right=Leaf})}),
             right=Leaf}),
       Int.compare,
       4);
*)

我希望我能提供帮助。如果您对此问题或代码有任何其他疑问,请询问。

答案 1 :(得分:0)

虽然乔恩的回答可能已经足够,但我发现它有点冗长。以下是尝试对问题进行较短的解释和回答:拥有BST和元素x,找到两个元素(SOME parent, SOME grandparent)(如果存在)。

我将使用的策略是:每当进行递归调用时,将parent记录为刚刚访问过的元素,将grandparent记录为前一个父元素。如果/当找到EQUALx的元素时,请返回当前可用的(parent, grandparent)

因为这两个额外的变量不是原始搜索功能的签名的一部分,并且因为我不想要它们,所以制作了本地函数helper

datatype 'a bst = Node of 'a * 'a bst * 'a bst
                | Leaf

fun search (initTree, compare, x) =
  let fun helper (tree, parent, grandparent) =
          case tree of
              Leaf           => (NONE, NONE)
            | Node (y, L, R) => case compare (x, y) of
                                    LESS    => helper (L, SOME y, parent)
                                  | GREATER => helper (R, SOME y, parent)
                                  | EQUAL   => (parent, grandparent)

  in helper (initTree, NONE, NONE) end

使用以下BST测试此功能:

val t = Node (5, Node (3, Node (2, Leaf, Leaf),
                          Node (4, Leaf, Leaf)),
                 Node (7, Node (6, Leaf, Leaf),
                          Node (8, Leaf, Leaf)))

我们看到了预期的结果:

- search (t, Int.compare, 2);
> val it = (SOME 3, SOME 5) : int option * int option
- search (t, Int.compare, 3);
> val it = (SOME 5, NONE) : int option * int option

不幸的是,此函数不会判断是否在BST的根目录中找到了某个元素,或者该元素是否存在。这是因为在这两种情况下都会返回(NONE, NONE)