-
An interesting podcast on failure! →
Just as I am introspecting whether there’s anything I have done that I can call ‘success’, I happened to listen to this interesting podcast on Failure in TED Radio hour. There is a lot to think about - success, impact, power - we know these attractive words and we probably have been measuring each of this using a completely wrong yard-stick. If we start thinking about the times we have failed and failed miserably, and how we have overcome some of the disastrous failures (that’s actually our success but we fail to realize it that way…), that is what prepares us for success and makes us powerful.
For those interested, below is a link to the podcast:
Hopefully, I will keep learning and continue to improve my work-in-progress project (my life) and get better every day of the project. -
Binary Trees again →
In the previous post, we saw how to define a binary tree. Now, that we have the tree, we need to be able to insert items into the tree. So, let us write an
insert
function to do that:If we want to insert an element
0
into an empty tree, we just do the following:Let us try something more fun. Let’s create a tree from a list. We have worked with lists all along and it is imaginable that we would accept inputs in the form of lists, but we want to implement our algorithms (later on!..) using tree data structure. So, this function is going to be very helpful. Let’s just call the function
make_tree
.Let us use our new function to create a tree from the list
[0; 1; 2]
.Wasn’t that super easy?
-
Binary Trees →
Let’s talk about Binary Trees - we cannot afford to ignore binary trees after having talked about several search algorithms. We will see many more applications of this wonderful data structure, but to get started, let’s understand what they are and how to create a simple one. Again, I am going to be using OCaml as I find it intuitive and concise. Probably, I will post the equivalent C/C++ code in later posts.
A Binary Tree is a tree in which each node can have at most two children
A binary tree is just a recursive data structure with a root node and two children, which themselves could be trees or leaf nodes (that have no children). Since the children could themselves be trees, we have this recursive data structure. For example,
node-0 / \ / \ node-1 node-2 / \ / \ / \ / \ leaf leaf leaf leaf
is how they generally look. Here,
node-0
hasnode-1
andnode-2
as child nodes, which themselves are binary trees (as they have two (‘bi’) children). It could use used to represent many things. For example, a family tree:Mother / \ / \ daughter Son / \ _ daughter
Let’s first define the type binary tree - we would call it just
tree
.This just defines the type
'a tree
- as noted in one of our earlier posts ‘a is like any - we could have integer trees, string trees, etc. that would take different type values. So, atree
could either be aLeaf
or anothertree
composed of two child trees and a root node ('a
). Now we can create a new empty tree with just a Leaf:Or we could create a tree with a root node and two child nodes, which themselves are trees with children:
I know it looks awkward, but let’s decompose it and understand.
Node (Leaf, 3, Leaf)
is one tree. Let’s call it C.Node (Leaf, 2, C)
is the next tree - Let’s call this guy B.Node (Leaf, 1, B)
is the other one. So, we have something like this:1 / \ / \ leaf 2 | / \ | / \ | -> B leaf 3 | | / \ |-> C | / \ | | leaf leaf | |
In the following post, we will write a functions to interact with this structure.
-
All permutations of a list →
Let’s write a sweet short function to generate all permutations of a list. We will be using some of the built-in functions of the OCaml List module - but these are generic and it could be implemented very easily (refer to the end of this post for sample implementations). One of them is the
map
function, that accepts an input function and a list and applies that function to each element of the list. For example, if we want to square each element of an input listlst
, call the functionsq_lst
:When we provide the function with a list
[1;2;3]
, we would obtain[1;4;9]
as the result.Another built-in function from the List module we would use is
flatten
, which just flattens a list of lists into a list. For example, if we want to flatten[[1; 2]; [3; 4]; [5]]
into a single list:Let’s focus back at the problem at hand - generating permutations of a list.
Permutation - all possible arrangements of a list of items, where order is important.
For example,
{a,b,c} {a,c,b} {b,a,c} {b,c,a} {c,a,b} {c,b,a}
are permutations of{a,b,c}
. Let’s approach this problem by first writing a function - let’s call itinsert
that would take two arguments - an elementx
to insert and a listlst
to insertx
into. And this functioninsert
would insertx
at all possible positions inlst
. For example, if we have a list[1;2]
and an element0
, we want to insert this0
at all possible positions in the list[1;2]
, producing[[0; 1; 2], [1; 0; 2], [1; 2; 0]]
- note that this is not the permutation, we are just inserting a given element into all possible positions in the list.Since we are producing a list of lists as output, for the base case we create a list of list containing a single element - the input element
x
. The second part just applies the function to each element of the list, besides adding the element to the list itself. So,x::lst
produces[0; 1; 2]
, and themap
part produces[1; 0; 2]
(which is applying the function to the first element1
of the list (h::el
) - the function just adds the element0
to the list head item1
giving1; 0
) and similarly[1; 2; 0]
.Now we will use this
insert
function to write ourperm
(for permutation) function, which is straight-forward given theinsert
function. We will just traverse the list and choose each item in the list and insert the item to all the positions of the rest of the list.Hope this was the most intuitive way to a permutation function.
Here’s a sample implementation of map and flatten functions - I creatively named them
mapp
andflatn
: -
Finding the minimum missing natural number - a better way! →
In one of the earlier posts we saw a straight forward way to find the minimum missing natural number in a list. That solution, although very straight forward, required us to sort the list before finding the minimum missing number. The question was - can we get away without that expense of sorting that list?
The answer seems to be yes. Since we know that we are not allowing any duplicates and we consider only natural numbers, we can use a very nice property:
In a perfectly consecutive sequence of natural numbers, any chosen number is also the number of natural numbers less than it.
That is, if we consider the consecutive sequence of number
0 1 2 3 4 5
and choose3
, we see that there are exactly three natural numbers before it -0 1 2
. A curious mind would have noted that these three numbers actually need not be in order - they should just exist. For example1 0 2 3 4 5
has three numbers before3
, they are not in sequence, but the fact that there are three of them assures us that nothing less than three is missing in the sequence. This is the property we are going to use to come up with a simpler search. Just like how we partitioned a list of numbers around a pivot element for quicksort, we will choose an elementx
and push all the numbers less than it (in any order) to the left of it and the rest to the right of it. We will also need to keep track of the number of elementsnum
to the left of the chosen number (in order to check our fancy property mentioned above). Let’s write the partition function first:If the number of elements tracked is equal to the chosen number, it just means that there is no missing number in the left partition (just like the example above where the number of elements less than
3
is equal to three, and we don’t have any missing natural number to the left of3
). Now, we will use this partition function to find the missing natural number:Think of
m
as the accumulator - we know that0
is the first natural number, so in case our input list is an empty one (base case), we just return the first (minimum) natural number that is missing. Is there too much going on in this? If you could work this out in a sample input, say[0; 3; 2; 9; 1]
it would help understand it better.