Filling a normal binary tree in ML with values - sml

Where let's say:
datatype bin_tree = Empty |
Node of value * bin_tree * bin_tree
How would I go about filling a binary tree (not a binary search tree where left is smaller than root and right bigger). Just values from a list inserted at each node in a binary tree.

You use the value constructors you've declared.
If we assume for a moment that value is int instead, then we for instance have that the tree
1
/ \
2 4
/
3
is represented by:
Node (1,
Node (2,
Node (3, Empty, Empty),
Empty
),
Node (4, Empty, Empty)
)
Or, equivalently, on one line:
Node (1, Node (2, Node (3, Empty, Empty), Empty), Node (4, Empty, Empty))

It's not really possible to help you, without knowing more about how you wan't your tree constructed from a given list. However here is an example that creates a balanced tree. It takes the first element and uses it as the node value, and then it splits the rest of the list into two sub lists of equal size (if possible), by taking all "even" element in the "left" list and all "odd" elements in the "right" list:
datatype 'a bin_tree = Empty
| Node of 'a * 'a bin_tree * 'a bin_tree
fun list_split xs =
let
fun loop [] (left, right) = (rev left, rev right)
| loop (x::y::xs) (left, right) = loop xs (x :: left, y :: right)
| loop (x :: xs) (left, right) = loop xs (x :: left, right)
in
loop xs ([], [])
end
fun built_tree [] = Empty
| built_tree (x :: xs) =
let
val (left, right) = list_split xs
val left_tree = built_tree left
val right_tree = built_tree right
in
Node (x, left_tree, right_tree)
end
The result:
- built_tree [1,2,3,4,5,6,7,8,9];
val it =
Node
(1,Node (2,Node (4,Node (8,Empty,Empty),Empty),Node (6,Empty,Empty)),
Node (3,Node (5,Node (9,Empty,Empty),Empty),Node (7,Empty,Empty)))
: int bin_tree

Here is an answer to the same question done in Java. This will probably help a good bit :).

Related

Haskell problem with potential workaround for empty lists

I defined a function that receives a data type and a list.
getAux :: (Ord a) => SparseArray a -> [Bool] -> (Value a)
getAux (Node x left right) index
| length(index) == 0 = x
| head(index) == False = getAux (left) (tail(index))
| head(index) == True = getAux (right) (tail(index))
I iterate through this function passing the tail of index
There are 3 possible returns: If the length of the list is less that or equal to 1 it returns x (the value stored in the node) If not it check the head of index and it calls getAux with the tail of index.
I tried to do a simple workaround to this issue by adding an extra element to the end of index when I call getAux. Instead of comparing if the length of index is equal to 0 I compare it with 1.
When I call the function I have:
getAux (Nodo x iz de) (num2bin(index) ++ [True])
The new getAux is:
getAux :: (Ord a) => SparseArray a -> [Bool] -> (Value a)
getAux (Node x left right) index
| length(index) == 1 = x
| head(index) == False = getAux (left) (tail(index))
| head(index) == True = getAux (right) (tail(index))
In both cases I get an error indicating that I can't do the head of an empty list
You call this with tail index, hence eventually you reach the empty list, hence that explains why for the latter, if length index == 1 fails, it will try to access head index and thus error.
But using length is not a good idea since it runs in O(n) with n the length of the list, and usually it is better to perform pattern matching on the list than to use head and tail, since then it is guaranteed that the list has a head and tail.
You can thus implement this as:
getAux :: SparseArray a -> [Bool] -> Value a
getAux (Node x _ _) [] = x
getAux (Node _ left right) (x:xs)
| x = getAux right xs
| otherwise = getAux left xs
By turining -Wincomplete-patterns [Haskell-docs] on for the compiler, it will warn you for patterns that the function does not cover. For example if your SparseArray has an extra data constructor, then these cases are not covered (yet).

verifying size of binary trees?

I have a datatype in this way
datatype 'a bin_tree =
Leaf of 'a
| Node of 'a bin_tree (* left tree *)
* int (* size of left tree *)
* int (* size of right tree *)
* 'a bin_tree (* right tree *)
so an example for correct tree would be:
val tree1 =
Node(Node(Node(Leaf 47, 1, 1, Leaf 38),
2,1,
Leaf 55),
3,2,
Node(Leaf 27, 1, 1, Leaf 96))
and an example for violating tree would be
val tree1false =
Node(Node(Node(Leaf 47, 1, 1, Leaf 38),
2,1,
Leaf 55),
4,2,
Node(Leaf 27, 1, 1, Leaf 96))
How can I write a predicate test such that
- test tree1;
val it = true : bool
- test tree1false;
val it = false : bool
This is a recursive problem. Before solving recursive problems on trees, it is a good idea to have a firm grasp on recursion on lists. You could say that trees are generalisations of lists, or that lists are special-cases of trees: lists have one tail, trees can have any number of tails depending on the type of tree. So here is how you could reconstruct and solve the problem using lists:
If, instead of the typical list definition, you have a list that also memoizes its own length:
(* datatype 'a list = [] | :: of 'a * 'a list *)
datatype 'a lenlist = Nil | Cons of int * 'a * 'a lenlist
Then you can test that the stored length is in accordance with the actual number of values.
I'll start by creating a function that counts to illustrate the part of the function that performs recursion:
(* For regular built-in lists *)
fun count0 [] = 0
| count0 (x::xs) = 1 + count0 xs
(* Counting the memoized list type disregarding the n *)
fun count1 Nil = 0
| count1 (Cons (n, x, xs)) = 1 + count1 xs
The next part is that I'd like, in each recursive step, to test that the stored number n is also in accordance with the actual counting. What is the return type of this function? Well, the test function that you want should be 'a lenlist -> bool and the count function that I made is 'a lenlist -> int.
I will suggest that you make a testcount that kinda does both. But you can do so in many ways, e.g. by giving it "extra arguments", or by giving it "extra return values". I will demonstrate both, just to show that sometimes one is better than the other and experience will tell you which.
Here is a val testcount1 : 'a lenlist -> bool * int function:
fun testcount1 Nil = (true, 0)
| testcount1 (Cons (n, x, xs)) =
let val (good_so_far, m) = testcount1 xs
val still_good = good_so_far andalso n = m + 1
in (still_good, m + 1)
end
val goodList = Cons (4, #"c", Cons (3, #"o", Cons (2, #"o", Cons (1, #"l", Nil))))
val badList = Cons (3, #"d", Cons (2, #"e", Cons (1, #"r", Cons (0, #"p", Nil))))
Testing this,
- testcount1 goodList;
> val it = (true, 4) : bool * int
- testcount1 badList;
> val it = (false, 4) : bool * int
This shows that testcount1 returns whether the numbers add up and the list's actual length, which was necessary during recursion to test that the numbers add up in each step, but in the end is no longer necessary. You could wrap this testcount function up in a simpler test function that only cares about the bool:
fun test xs = #1 (testcount1 xs)
Here is another way to go about: There is something not so satisfying with the way testcount1 recurses. It keeps calculating the m + 1s even though it is able to determine that a list (e.g. at Cons (0, #"p", Nil)) is broken.
Here is an alternate val testcount2 : 'a lenlist * int -> bool that stores a number in an extra argument instead:
fun testcount2 (Nil, 0) = true
| testcount2 (Nil, _) = false
| testcount2 (Cons (n, x, xs), m) =
n = m andalso testcount2 (xs, m - 1)
This seems a lot neater to me: The function is tail-recursive, and it stops immediately when it senses that something is fishy. So it doesn't need to traverse the entire list if it's broken at the head. The downside is that it needs to know the length, which we don't know yet. But we can compensate by assuming that whatever is advertised is correct until it's clearly the case, or not.
Testing this function, you need to not only give it a goodList or a badList but also an m:
- testcount2 (goodList, 4);
> val it = true : bool
- testcount2 (badList, 4);
> val it = false : bool
- testcount2 (badList, 3);
> val it = false : bool
It's important that this function doesn't just compare n = m, since in badList, that'd result in agreeing that badList is 3 elements long, since n = m is true for each iteration in all Cons cases. This is helped in the two Nil cases that require us to have reached 0 and not e.g. ~1 as is the case for badList.
This function can also be wrapped inside test to hide the fact that we feed it an extra argument derived from the 'a lenlist itself:
fun size Nil = 0
| size (Cons (n, _, _)) = n
fun test xs = testcount2 (xs, size xs)
Some morals so far:
Sometimes it is necessary to create helper functions to solve your initial problem.
Those helper functions are not restricted to have the same type signature as the function you deliver (whether this is for an exercise in school, or for an external API/library).
Sometimes it helps to extend the type that your function returns.
Sometimes it helps to extend the arguments of your functions.
Just because your task is "Write a function foo -> bar", this does not mean that you cannot create this by composing functions that return a great deal more or less than foo or bar.
Now, for some hints for solving this on binary trees:
Repeating the data type,
datatype 'a bin_tree =
Leaf of 'a
| Node of 'a bin_tree (* left tree *)
* int (* size of left tree *)
* int (* size of right tree *)
* 'a bin_tree (* right tree *)
You can start by constructing a skeleton for your function based on the ideas above:
fun testcount3 (Leaf x, ...) = ...
| testcount3 (Leaf x, ...) = ...
| testcount3 (Node (left, leftC, rightC, right), ...) = ...
I've embedded som hints here:
Your solution should probably contain pattern matches against Leaf x and Node (left, leftC, rightC, right). And given the "extra argument" type of solution (which at least proved nice for lists, but we'll see) needed two Leaf x cases. Why was that?
If, in the case of lists, the "extra argument" m represents the expected length of the list, then what would an "extra argument" represent in the case of trees? You can't say "it's the length of the list", since it's a tree. How do you capture the part where a tree branches?
If this is still too difficult, consider solving the problem for lists without copy-pasting. That is, you're allowed to look at the solutions in this answer (but try not to), but you're not allowed to copy-paste code. You have to type it if you want to copy it.
As a start, try to define the helper function size that was used to produce test from testcount2, but for trees. So maybe call it sizeTree to avoid the name overlap, but other than that, try and make it resemble. Here's a skeleton:
fun sizeTree (Leaf x) = ...
| sizeTree (Node (left, leftC, rightC, right)) = ...
Sticking testcount3 and sizeTree together, once written, should be easy as tau.

How can I create a ternary tree in SMLNJ?

Right now I have a binary tree modeled in SMLNJ however I want to change this model to where there is a tree inside of tree inside of tree. (Ternary Tree)
If you begin with the root of a binary tree.
Binode with an (id1*(binode)) ß- a binary tree
Then if that “binode” is located as part of a tuple: 2Dbinode
That tuple has an identifier and that binode with is the root of the binode tree.
2Dbinode (id2* (binode) *2Dbinode)
Each of those in turn are part of a 3Dbinode which consists of:
3Dbinode(id3 * (2Dbinode) * 3Dbinode)
For ex. 3Dbinode(id3 * (2Dbinode) * 3Dbinode) the root 3Dbinode might contain the following data:
(25, (7, (11)))
And by adding the nodes (25, (7, (22)))
(25, (10, (4))), (30, (7, (22)))
3DBinary Tree Model
Here is SMLNJ code for the 2D binary tree I am modifying.
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);
I need to populate the data structure with N randomized (3Dnodes):
How can I implement these functions?
Search for a specific node displaying the path to the node ex: (25, 10, 4) the display would be
(25)
(25, 7)
(25, 10)
(25, 10,4)
If the user searches for a node that does not exist:
(30, (7, (30))) then the path displayed would be
(25)
(30)
(30,7)
(30, 7, 30) NOT FOUND
If the user wishes to ADD a node at any level they should be prompted to enter the 3 digit code for that node; Again the path should be displayed.
EX: ADD (30, 11, 5) then the display would be
(25)
(30)
(30, 7)
(30, 11) created
(30, 11, 5) created
Print out the contents of the 3dbinode tree as a sequence of (A,B,C)
DELETE a node
Delete a node: EX: DEL (30, 7, _)
Then the result would be
- (30, 7, 22) deleted
- (30, 7, 0) created
Ternary tree?
Edit 2: After you reviewed your question, it still seems unclear how you wish to navigate this ternary tree when searching it. A binary search tree divides its elements left and right depending on which one is greater. You have described no similar criterion: When should your functions use the first, second and third branch?
Edit 3: I've provided the function pathExists that works on ternary trees, but AddNode is still missing as you have not provided any insight into the questions that I've highlighted with bold. If your tree really does serve the purpose of containing points in a 3-dimensional space, it does sound like you want a k-d tree, as I suggested once. I've also partially provided the function make3DTree under the assumption that a k-d tree is what you're looking for.
Until I saw the drawing you made of a ternary tree (or generally an n-ary tree), I could not understand your question. A ternary tree simply has (up to) three child nodes at each level instead of the binary tree's two.
The wording "tree inside of a tree inside of a tree" means something different than the branching factor (2, 3, n). Exactly how you turn the triples (25, 7, 11), (25, 7, 22), (25, 10, 4), and (30, 7, 22) into your ternary tree is still a little puzzling to me. It seems that the bottom nodes only have two empty leaves. I will interpret this as if there were a third empty arrow in the middle.
Your AddNode function constructs binary search trees where the smaller elements go to the left, and the larger elements to the right. But how, then, do you wish to use a third branch?
Compare the following generic / integer-specific binary tree datatype definitions,
datatype 'a btree = BTreeEmpty | BTreeNode of 'a * 'a btree * 'a btree
datatype int_btree = BTreeEmpty | BtreeNode of 'a * int_btree * int_btree
with the ones for ternary trees,
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
or even ones that support variable branching in each node,
datatype 'a tree = TreeEmpty | TreeNode of 'a * 'a tree list
datatype int_tree = TreeEmpty | TreeNode of int * int_tree list
Creating the ternary tree you depicted,
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
although it would probably be more convenient with a function like AddNode, only you need to specify a consistent way for elements to be added to this kind of tree. How does the binary search tree logic translate to ternary trees?
Determining if a path exists in a ternary tree
You can determine if a path to a node exists. Since a tree can have any depth, a path can have any length and should be represented with a list. The path [25, 7, 10, 4] exists in your ternary tree, for example.
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)
Testing this function with treeModel above:
- 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
Inserting a point in a ternary tree [???]
A template for this function could be
fun AddNode (x, TTreeEmpty) = TTreeNode (x, TTreeEmpty, TTreeEmpty, TTreeEmpty)
| AddNode (x, TTreeNode (y, subtree1, subtree2, subtree3))) = ???
but if x <> y, which of the three subtrees should it try to add x to?
K-d tree?
Edit 1: After having answered, I realize that perhaps you are looking for a k-d tree? A k-d tree can store k-dimensional vectors, using only binary trees, in a way that allows efficient, locality-specific lookups.
The great trick here is to say that the 1st level of the tree divides the space into two halves on the X-axis, the 2nd level of the tree divides the left/right halves into halves on the Y-axis, the 3rd level of the tree divides the left/right halves into halves on the Z-axis, the 4th level on the X-axis again, the 5th level on the Y-axis again, and so on.
Here is an initial translation of that pseudocode for k = 3 into Standard 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
One optimization could be to reduce the constant re-sorting.
Adding a single 3D point to this tree is well-defined, but does not guarantee that the tree is particularly balanced:
(* 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
Determining if a point exists in this tree can be achieved by performing a nearest-neighbor search, which is slightly less trivial to implement.

I want to make function maptree with standard ML

I want to make function maptree with standard ML.
If function f(x) = x + 1;
then
maptree(f, NODE(NODE(LEAF 1,LEAF 2),LEAF 3));
should make result
NODE(NODE(LEAF 2,LEAF 3),LEAF 4))
I write the code like below.
datatype 'a tree = LEAF of 'a | NODE of 'a tree * 'a tree;
fun f(x) = x + 1;
fun maptree(f, NODE(X, Y)) = NODE(maptree(f, X), maptree(f, Y))
| maptree(f, LEAF(X)) = LEAF(f X);
but when I execute this code like this
maptree(f, (NODE(NODE(LEAF 1,LEAF 2),LEAF 3)));
result is not I want to
(NODE(NODE(LEAF 2,LEAF 3),LEAF 4)))
but
NODE(NODE(LEAF #,LEAF #),LEAF 4)).
Why this happened(not a number but #)?
# is used by the REPL when the data structure it prints is deeper than a pre-set value. If you increase that value, you'll get the result you excepted. I assume you're using SML/NJ, which calls that setting print.depth:
sml -Cprint.depth=20
- maptree(f, (NODE(NODE(LEAF 1,LEAF 2),LEAF 3)));
val it = NODE (NODE (LEAF 2,LEAF 3),LEAF 4) : int tree
You can find more options like these by executing sml -H. Look them up under the "compiler print settings" section:
compiler print settings:
print.depth (max print depth)
print.length (max print length)
print.string-depth (max string print depth)
print.intinf-depth (max IntInf.int print depth)
print.loop (print loop)
print.signatures (max signature expansion depth)
print.opens (print `open')
print.linewidth (line-width hint for pretty printer)
Some comments:
I would probably go with the definition
datatype 'a tree = Leaf | Node of 'a tree * 'a * 'a tree
so that trees with zero or two elements can also be expressed.
I would probably curry the tree map function
fun treemap f Leaf = Leaf
| treemap f (Node (l, x, r)) = Node (treemap f l, x, treemap f r)
since you can then partially apply it, e.g. like:
(* 'abstree t' returns t where all numbers are made positive *)
val abstree = treemap Int.abs
(* 'makeFullTree n' returns a full binary tree of size n *)
fun makeFullTree 0 = Leaf
| makeFullTree n =
let val subtree = makeFullTree (n-1)
in Node (subtree, n, subtree)
end
(* 'treetree t' makes an int tree into a tree of full trees! *)
val treetree = treemap makeFullTree
You may at some point want to fold a tree, too.

Biggest and smallest element of a binary tree haskell

Consider the following definition of trees:
Data Tree a = Empty | Node a (Tree a) (Tree a)
Define the function smallerbigger :: Float -> Tree Float -> ([Float],[Float]) that given a number n and a tree, produces a pair of lists whose elements are smaller and bigger than n.
(the question initially stated that the tree is a search tree, which was done in error).
For a list, you could implement a similar algorithm as
smallerbigger :: Ord a => a -> [a] -> ([a], [a])
smallerbigger x xs = go x xs [] []
where
go y [] lt gt = (lt, gt)
go y (z:zs) lt gt
| z < y = go y zs (z:lt) gt
| z >= y = go y zs lt (z:gt)
The basic shape of the algorithm will remain the same for a Tree, but the biggest difference will be how you recurse. You'll need to recurse down both branches, then once you get the result from each branch concatenate them together along with the result from the current node.
If you get stuck implementing this for a tree, feel free to comment and let me know what problem you're experiencing and include a link to your code in a gist/pastebin/whatever.
Here little set of utilities leading to simple solution. Assuming you need lazy function.
Here your data defition with addition of only show ability for debug
data Tree a = Empty | Node a (Tree a) (Tree a) deriving Show
Next we need to a little utility for easy tree creating. Following code is building a very unbalanced tree that is very similar to original list.
fromList:: [a] -> Tree a
fromList [] = Empty
fromList (x:xs) = Node x Empty (fromList xs)
Simple and obvious representation of tree in list form. Order of elements is preserved.
asList:: Tree a -> [a]
asList Empty = []
asList (Node x left right) = asList left ++ x: asList right
Next we assume we'll need pair of lists that could be lazy regardless of our destination.
We are keeping ability to work with tree that has infinite structure somewhere in the middle, but not at the last or end element.
This definition to walk our tree in opposite direction in lazy manner.
reverseTree:: Tree a -> Tree a
reverseTree Empty = Empty
reverseTree (Node x left right) = Node x (reverseTree right) (reverseTree left)
Next we finally building our procedure. It could create two possible infinite list of elements smaller and bigger than first argument.
smallerbigger::Ord a => a-> Tree a -> ([a],[a])
smallerbigger p t = (takeWhile (<p) $ asList t, takeWhile (>p) $ asList $ reverseTree t)
main = let t = fromList [1..10]
in do
print t
print $ smallerbigger 7 t
But in other hand we may want to preserve order in second list, while we are sure that we never hit bottom building first list. So we could drop elements that are equal to target separator and just span out list at it.
smallerbigger p = span (<p) . filter(/=p) . asList
Thanks for all the help and suggestions.
I managed to find a different solution:
smallerbigger :: Ord a => a -> Tree a -> ([a], [a])
smallerbigger n (Node r e d) =
let (e1,e2) = smallerbigger n e
(d1,d2) = smallerbigger n d
in if r>n then ( e1++d1, r:(e2++d2))
else if r<n then (r:(e1++d1), e2++d2 )
else ( e1++d1, e2++d2 )