everyone! I have a list type:
type ConsList<'value> =
| Cons of head: 'value * tail: ConsList<'value>
| Empty
And a tree type:
type Tree<'value> =
| Node of value: 'value * children: ConsList<Tree<'value>>
| Leaf of value: 'value
I would like a function that could collect all values in nodes and leaves of a Tree and convert them into a ConsList in order starting from the root and following from left to right.
For example, if I have: Node(1, Cons(Leaf 2, Cons(Leaf 3, Empty)))
Then I expect the output to be: Cons(1, Cons(2, Cons(3, Empty)))
I have fold-functions, if they can be useful:
let rec fold folder acc lst =
let f = fold folder
match lst with
| Empty -> acc
| Cons (hd, tl) -> f (folder acc hd) tl
let rec fold folder acc tree =
let f = fold folder
match tree with
| Leaf value -> folder acc value
| Node(value, children) -> ConsList.fold f (folder acc value) children
Use the tree fold to build up a list of values. Something like this:
Tree.fold (fun currentStateOfList value ->
// add value to currentStateOfList here
) initialStateOfList aTree
You need to figure out:
What is the initial state of the list?
What should be done to add a value to the current state of the list?
Depending on the requirements, you might also have to reverse the order of the list at the end.
If I had an n-ary tree, it might "look" something like the following.
----1--------------------
/ \ \
---2--- ---3---- --4--
/ / \ / / \ \ / \
5 6 7 8 9 10 11 12 --13--
/ \
14 15
My F# is not great, but I'm reasonably proficient in OCaml, so this type might look something like the following, if I don't define my own list type.
type 'a tree = Node of 'a | Tree of 'a * 'a tree list
Creating the above structure is then:
Tree (1,
[Tree (2, [Node 5; Node 6; Node 7]);
Tree (3, [Node 8; Node 9; Node 10; Node 11]);
Tree (4, [Node 12; Tree (13, [Node 14; Node 15])])])
To convert this to a list in a depth-first manner, and to preserve tail-recursion, a stack-based algorithm can be employed. As we iterate through, we keep a stack of tree values to evaluate in turn.
For the above example, we'd cons 1 onto a result list, then recursively call tree_to_list function on:
---2---
/ / \
5 6 7
While putting the remainder of the children on the stack.
---3---- --4--
/ / \ \ / \
8 9 10 11 12 --13--
/ \
14 15
Encountering a Node, we'd cons the value onto the result list, and store the remaining trees (boths Nodes) on the stack.
6 7 ---3---- --4--
/ / \ \ / \
8 9 10 11 12 --13--
/ \
14 15
Now we begin consuming the stack. The 6 and 7 nodes go first, then we start with the 3 Tree.
9 10 11 --4--
/ \
12 --13--
/ \
14 15
And then eventually consume the 4 Tree until we hit a Node or a Tree with no children (really the same thing) and the stack is empty. Then, because we've been building up the list backwards for efficiency, we need to reverse it.
A straightforward implementation might look like:
let tree_to_list t =
let rec tree_to_list' t a s =
match t, s with
| (Node v | Tree (v, [])), [] -> List.rev (v :: a)
| Node v, x::xs -> tree_to_list' x (v :: a) xs
| Tree (v, x::xs), _ -> tree_to_list' x (v :: a) (xs # s)
| Tree (v, []), s::ss -> tree_to_list' s (v :: a) ss
in
tree_to_list' t [] []
Given the close relation between the languages, hopefully you will find this algorithm readily applicable.
Related
Description of the problem
I have a lazy infinite binary tree:
type 'a tree_node = TN of 'a * 'a inf_btree * 'a inf_btree
and 'a inf_btree = 'a tree_node Lazy.t
let rec ibt_map (f : 'a -> 'b) (t : 'a inf_btree) : 'b inf_btree =
let TN (x, ltree, rtree) = Lazy.force t in
lazy (TN (f x, ibt_map f ltree, ibt_map f rtree))
let rec example : int inf_btree =
lazy (TN (1,
ibt_map ((+) 1) example,
ibt_map ((+) 2) example
)
)
;;
and a lazy stream:
type 'a link_node = LN of 'a * 'a stream
and 'a stream = 'a link_node Lazy.t
Now I want to transform a tree into a stream, in such a way that it preserves the order of the elements in the tree. More precisely, I want elements close to the root to come early in the stream. However, if it's done depth-first then half the tree will never occur in the stream:
let df_tree_to_stream (t : 'a inf_btree) : 'a stream =
let TN (x, ltree, rtree) = Lazy.force t in
let substream1 = df_tree_to_stream ltree in
let substream2 = df_tree_to_stream rtree in
lazy (LN (x, substream1))
(* how to work in substream2 ??? *)
An attempted solution by alternation
We could try to merge the two streams so that they alternate, but then the order of the elements will not be preserved. In the given example, the tree looks like
1
3 2
5 6 4 3
.........
The order of the stream should be
1, 3, 2, 5, 6, 4, 3, ...
But if we simply alternate the streams returned by subtrees, then the tree rooted at 3 would have streams that start with 5 and 6. So this subtree transforms into the stream 3, 5, 6 ... The other subtree becomes 2, 4, 3 ... So the overall resulting stream would be
1, 3, 2, 5, 4, ...
We could instead manage the order of visitation of nodes in the tree by maintaining a queue.
Question
My question is, is there simpler a way? Can we get the desired order not using a queue and only using recursion?
It is unusual to try to get away from the tail recursive version, but yes you can hide the queue of the breadth first traversal in a call stack. For instance, you can define an interleave function that switches the left and right source with decreasing frequency:
let rec interleave first period count l r () =
if count = 0 then
if first then
interleave false period period r l ()
else
let period = 2 * period in
interleave true period period r l ()
else
match l () with
| Seq.Nil -> r ()
| Seq.Cons(y,l) ->
Seq.Cons(y, interleave first period (count-1) l r)
let interleave = interleave true 1 1
let rec to_seq tree () =
let lazy (TN(x,l,r)) = tree in
Seq.Cons(x, interleave (to_seq l) (to_seq r))
I have a few problems creating a tree size function with type 'a option tree -> int
type 'a tree = Leaf of 'a
| Fork of 'a * 'a tree * 'a tree
How would I create a t_opt_size function with type 'a option tree -> int?
I know I would have to use Some and the None operate.
I have this so far, but it's complicated to match with the option type.
let rec t_size (tr: 'a tree): int =
match tr with
| Leaf _ -> 1
| Fork (_, t1, t2) -> t_size t1 + t_size t2 + 1
I assume from your comments that you want a leaf that looks like (Leaf None) not to be counted in your tree size calculation.
Seems like the key is to split this:
| Leaf _ -> 1
Into two cases:
| Leaf None -> (* Left as exercise *)
| Leaf (Some _) -> (* Left as exercise *)
Since OCaml will take the first match, you can abbreviate this as follows if you like:
| Leaf None -> (* Left as exercise *)
| Leaf _ -> (* Left as exercise *)
You should make a similar change to the Fork case, though I have to say that Fork (None, l, r) doesn't really work for constructing a search tree.
If you want to generalize, you might need to write a generic tree walker which accepts a visitor function. I recommend you try to implement fold_tree, which accepts: (1) a fold function, taking some value, a tree and producing a new result ('a -> 'b t -> 'c), (2) an initial element of type 'a as well as (3) a tree. Then, fold_tree returns a value of type 'c.
Then, you should be able to call fold_tree with a function that skips over None leaves but otherwise increment the count like you did.
If you don't want to count all values in the tree as 1, but each depending on its contents, write a function that determines the count per value and use that:
let weight = function
| _ -> 1 (* or anything else *)
let rec t_opt_size (tr: 'a tree): int = match tr with
| Leaf v -> weight v
| Fork (v, t1, t2) -> t_size t1 + t_size t2 + weight v
You even might want to generalise and pass the weight function as a parameter to t_size instead of writing different size functions that all use their own weighting.
This is only part of my huffman tree generated using ocaml. The tree is represented as (char*int list) list:
[(' ', [0]); ('e', [1; 0]); ('t', [1; 1; 0]); ('a', [1; 1; 1; 0]);
('o', [1; 1; 1; 1; 0]); ('n', [1; 1; 1; 1; 1; 0]).....].
The (char*int list) is the code and the corresponding encoded bitstream. I'm wondering if this is a correct tree or I understood something wrong. In this way, the longest encoded ASC II code will be 255 bits. The original file is 213.3k and after encoding, it becomes 227k while in the instructions, I was told it should generate a file around 119k. I don't know where my problem is because I did everything following the instructions. Can someone tell me what is wrong in here?
My biggest problem is that: if I use huffman coding, only the 8 most frequent chars can save me space while the other 247 chars will cost extra space, is that true? If it isn't, why?
The codes I wrote was following the instructions in this link:
http://www.cs.cornell.edu/Courses/cs3110/2012sp/hw/ps3/ps3.html
This is my code of encoding function:
type huffmantree = Node of huffmantree*(int*int)*huffmantree
| Leaf of char*int | Nil
type encoding = char * (int list)
let look_up (chr: char) (encl : encoding list) : int list =
let rec look_up_rec encl =
match encl with
| [] -> raise (Failure "Not found")
| (ch,theL)::tl -> if ch = chr then theL
else look_up_rec tl
in
look_up_rec encl
;;
let get_codes (hm : huffmantree): encoding list =
let rec get_codes_rec aTree word=
match aTree with
| Nil -> []
| Node (Leaf(lKey,lFreq),value,Nil) -> [(lKey,[0])]
| Node (Leaf(lKey,lFreq),value,Leaf(rKey,rFreq)) ->
[(lKey,List.append word [0]);(rKey,List.append word [1])]
| Node (Leaf(lKey,lFreq),value,rNode) ->
(lKey,List.append word [0])::(get_codes_rec rNode (List.append word [1]))
in
get_codes_rec hm []
;;
let encode (text : char list) : huffmantree * int list =
let sortedT = List.fast_sort (fun ch1 ch2->
if (int_of_char ch1)>=(int_of_char) ch2 then 1 else -1) text
in
let rec cre_freq_list aList m =
match aList with
| [] -> []
| hd::[] -> [(hd,m+1)]
| hd1::hd2::tl -> if hd1=hd2 then cre_freq_list (hd2::tl) (m+1)
else (hd1,(m+1))::(cre_freq_list (hd2::tl) 0)
in
let sortedF = List.fast_sort (fun (ch1,fr1) (ch2,fr2) ->
if fr1>=fr2 then 1 else -1) (cre_freq_list sortedT 0)
in
let rec createHuff sortedF=
match sortedF with
| [] -> Nil
| (ch,va)::[] -> Node (Leaf (ch,va),(256,va),Nil)
| (ach,aval)::tl ->
let rec creH_rec the_tl sib n freq=
match the_tl with
| (bch,bval)::[] -> Node(Leaf (bch,bval),(n,bval+freq),sib)
| (bch,bval)::btl -> creH_rec btl
(Node (Leaf (bch,bval),(n,bval+freq),sib)) (n+1)
(freq+bval)
in creH_rec tl (Leaf(ach,aval)) 256 aval
in
let huff = createHuff sortedF
in
let rec make_codes text =
match text with
| [] -> []
| hd::tl -> List.append (look_up hd (get_codes huff))
(make_codes tl)
in
(huff,(make_codes text))
Looking at the resulting tree, it appears that you don't implement the Huffman's algorithm. I doubt the 'e' is more frequent in your text than any other letter. Without your code I can only guess but maybe when merging the two lightest trees you inserted the resulting tree at the end of the list of trees to merge instead of inserting it at the right place according to its weight.
In your code createHuff is declared recursive but there is no recursive call.
Your function createHuff never compares the values inside the sortedF list don't you think this is a problem? It means that createHuff will always yield the same tree (with different labels but with the same structure).
I know that xs !! n gives me nth element in a list, but I don't know how to edit nth element in that list. Can you tell me how can I edit nth element in a list or give a hint at least?
For example how can I make the second element 'a' an 'e' in this: ['s','t','a','c','k']?
Changing the nth element
A common operation in many languages is to assign to an indexed position in an array. In python you might:
>>> a = [1,2,3,4,5]
>>> a[3] = 9
>>> a
[1, 2, 3, 9, 5]
The
lens package gives this functionality with the (.~) operator. Though unlike in python the original list is not mutated, rather a new list is returned.
> let a = [1,2,3,4,5]
> a & element 3 .~ 9
[1,2,3,9,5]
> a
[1,2,3,4,5]
element 3 .~ 9 is just a function and the (&) operator, part of the
lens package, is just reverse function application. Here it is with more common function application.
> (element 3 .~ 9) [1,2,3,4,5]
[1,2,3,9,5]
Assignment again works perfectly fine with arbitrary nesting of Traversables.
> [[1,2,3],[4,5,6]] & element 0 . element 1 .~ 9
[[1,9,3],[4,5,6]]
or
> set (element 3) 9 [1,2,3,4,5,6,7]
Or if you want to effect multiple elements you can use:
> over (elements (>3)) (const 99) [1,2,3,4,5,6,7]
> [1,2,3,4,99,99,99]
Working with types other then lists
This is not just limited to lists however, it will work with any datatype that is an instance of the Traversable typeclass.
Take for example the same technique works on trees form the standard
containers package.
> import Data.Tree
> :{
let
tree = Node 1 [
Node 2 [Node 4[], Node 5 []]
, Node 3 [Node 6 [], Node 7 []]
]
:}
> putStrLn . drawTree . fmap show $ tree
1
|
+- 2
| |
| +- 4
| |
| `- 5
|
`- 3
|
+- 6
|
`- 7
> putStrLn . drawTree . fmap show $ tree & element 1 .~ 99
1
|
+- 99
| |
| +- 4
| |
| `- 5
|
`- 3
|
+- 6
|
`- 7
> putStrLn . drawTree . fmap show $ tree & element 3 .~ 99
1
|
+- 2
| |
| +- 4
| |
| `- 99
|
`- 3
|
+- 6
|
`- 7
> putStrLn . drawTree . fmap show $ over (elements (>3)) (const 99) tree
1
|
+- 2
| |
| +- 4
| |
| `- 5
|
`- 99
|
+- 99
|
`- 99
Because Haskell is a functional language, you cannot 'edit' elements in lists, because everything is immutable. Instead, you can create a new list with something like:
take n xs ++ [newElement] ++ drop (n + 1) xs
However, it is not recommended in Haskell. For some more information you can see this post: Haskell replace element in list
You can't edit the nth element of a list, values are immutable. You have to create a new list. But due to the immutability, it can share the part after the changed element with the original list.
So if you want to apply a transformation to the nth element of a list (and have the parts before and after identical), you have three parts
the front of the list before the element in question, say front
the element in question, say element
the back of the list after the element in question, say back.
Then you'd assemble the parts
front ++ transform element : back
so it remains to get a hold on the interesting parts in a nice way.
splitAt :: Int -> [a] -> ([a],[a])
does that, splitAt idx list gives back the first part of the list, before the index idx as the first component of the pair, and the rest as the second, so
changeNthElement :: Int -> (a -> a) -> [a] -> [a]
changeNthElement idx transform list
| idx < 0 = list
| otherwise = case spliAt idx list of
(front, element:back) -> front ++ transform element : back
_ -> list -- if the list doesn't have an element at index idx
(Note: I have started counting elements at 0, if you want to start counting at 1, you need to adjust and use idx-1.)
I' surprised the following method was not yet mentioned, so I will add it for further reference:
replace index elem = map (\(index', elem') -> if index' == index then elem else elem') . zip [0..]
> replace 2 'e' "stack"
"steck"
It handle the casse of out of range index.
> replace (-1) 'z' "abc"
"abc"
> replace 0 'z' "abc"
"zbc"
> replace 2 'z' "abc"
"abz"
> replace 3 'z' "abc"
"abc"
It is not slower than the splitAt method ( O(2N) ).
There is also the possibility of writing a simple recursive solution.
The basic idea is that, in order to substitute element #5 in a list, you just have to substitute element #4 in the tail of that list.
Using the notations from the answer of #DanielFisher, this gives the following code:
changeNthElement :: Int -> (a -> a) -> [a] -> [a]
changeNthElement n fn [] = [] -- nothing to change
changeNthElement n fn (x:xs)
| (n < 0) = x:xs -- no change for a negative index
| (n == 0) = (fn x) : xs -- easy case
| otherwise = x : (changeNthElement (n-1) fn xs) -- recursion
If the new value does not depend on the old one, one can specialize the above function:
setNthElement :: Int -> a -> [a] -> [a]
setNthElement n v xs = changeNthElement n (const v) xs
Testing:
$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/ :? for help
...
λ>
λ> :load q15530511.hs
[1 of 1] Compiling Main ( q15530511.hs, interpreted )
Ok, one module loaded.
λ>
λ> xs = replicate 10 7
λ>
λ> xs
[7,7,7,7,7,7,7,7,7,7]
λ>
λ> changeNthElement 3 (+2) xs
[7,7,7,9,7,7,7,7,7,7]
λ>
λ> setNthElement 2 42 xs
[7,7,42,7,7,7,7,7,7,7]
λ>
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 :).