Reputation: 1305
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
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
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