luthien
luthien

Reputation: 1305

Find ancestors of node in BST in Standard ML

I'm trying to find the parent and grandparent of a node in a BST in SML.

I have tried to modify this function:

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 

by changing the format of the input, the comparison and the output:

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)

Obviously it's not working and I suppose there is a simpler way to do this.

I added a new variable in order to save the current father of each node I'm checking and it works, however it's difficult (for me) to find a way to also keep the grandfather of the node I check.

Any ideas? Thanks in advance.

Upvotes: 1

Views: 534

Answers (2)

sshine
sshine

Reputation: 16105

While joom's answer is probably sufficient, I find it a little verbose. Here is an attempt to write a shorter interpretation of and answer to the problem: Having a BST and an element x, find the two elements (SOME parent, SOME grandparent) if they exist.

The strategy I will use is this: Whenever a recursive call is made, record parent as the element that was just visited and grandparent as the previous parent. If/when an element is found that is EQUAL to x, return the currently available (parent, grandparent).

Because these two additional variables are not part of the original search function's signature, and because I don't want them to be, the local function helper is made.

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

Testing this function using the following 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)))

We see the expected results:

- 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

Unfortunately, this function will not tell whether an element was found in the root of the BST or did not exist. That is because (NONE, NONE) is returned in both cases.

Upvotes: 0

Joomy Korkut
Joomy Korkut

Reputation: 514

First of all, your search function was not working properly, so I cleaned it up a little bit. In order to avoid unbound type variable in type declaration error, you have to define your bst type as 'a bst. I also fixed a paranthesis error. Here is my version of your search function:

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);
*)

Since you want a function that returns the parent and grandparent nodes of your search, you need a function that returns a tuple of these: (search node, parent of the search node, grandparent of the search node). However, you will not always have a parent or grandparent. For example, if the key you are looking for is already at the root of your main tree, you will not have a parent or grandparent. Because of that, you need to use the option type. This will help you return NONE as the parent node if there is no parent node for that search. Now, all you need to do is to start the search with (your main tree, NONE, NONE) and then as you move along the tree, shift the parent nodes to the right. If you don't find the key, just return a triplet of NONE. Here is the code for that:

(*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);
*)

I hope I could help. Please ask if you have any other questions on this issue or code.

Upvotes: 1

Related Questions