Introduction
Consider the following code to compute the height of a binary tree.
struct Tree{ Tree* left; Tree* right; int val; }; struct Recursive { static int height(Tree* root){ if(root){ auto lh = height(root->left); auto rh = height(root->right); return 1 + std::max(lh,rh); }else{ return 0; } } };
This code builds up the stack which is a scarce resource compared to the heap. An iterative solution is shown below:
struct Iterative { static int height(Tree *root){ enum class item_type { tree, height}; struct item { item_type type; union { Tree* root; unsigned height; }; item(Tree* r):type(item_type::tree) {root=r;} item(unsigned h):type(item_type::height) {height=h;} }; bool go_on=true; unsigned depth = 0; std::stack<item> items; while (go_on) { if (root) { item it(root->right); items.push(it); root = root->left; } else { go_on=false; depth=0; while (!items.empty()&& !go_on) { item cur = items.top(); items.pop(); switch (cur.type) { case item_type::tree: { item next(depth); items.push(next); root = cur.root; go_on = true; } break; case item_type::height: { depth = 1 + std::max(depth, cur.height); //depth = 1 + depth + cur.height; } break; } } } } return depth; } };
The rest of the blog documents my journey from an OCaml solution to a C++ version. I started with attempting to have a tail recursive solution in OCaml. This lead me to CPS (continuation passing style). The CPS version was then defunctionalized to two mutually recursive functions that was then translated to C++ and then inlined to the iterative method shown above.
Continuation Passing Style
The recursive OCaml solution is shown below:
type 'a tree = Leaf of a' | Node of a' * a' tree * a' tree;;
let depth = function
| Leaf x -> 0
| Node(_, left,right) ->
let l = depth left in
let r = depth right in
1 + (max l r)
The CPS modification as Gasche suggests is straightforward as shown below:
let depth tree = let rec depth tree k = match tree with | Leaf x -> k 0 | Node(_,left,right) -> depth left (fun dleft -> depth right (fun dright -> k (1 + (max dleft dright)))) in depth tree (fun d -> d)
Gasche then defunctionalizes the above code as follows:
type ('a, 'b) cont = | Kleft of 'a tree * ('a, 'b) cont (* right and k *) | Kright of 'b * ('a, 'b) cont (* dleft and k *) | Kid
let depth tree = let rec depth tree k = match tree with | Leaf x -> eval k 0 | Node(_,left,right) -> depth left (Kleft(right, k)) and eval k d = match k with | Kleft(right, k) -> depth right (Kright(d, k)) | Kright(dleft, k) -> eval k (1 + max d dleft) | Kid -> d in depth tree Kid ;;
As Gasche points out cont
is essentially a linked list and hence the above code can be transformed as shown below:
type ('a, 'b) next_item = | Kleft of 'a tree | Kright of 'b type ('a, 'b) cont = ('a, 'b) next_item list let depth tree = let rec depth tree k = match tree with | Leaf x -> eval k 0 | Node(_,left,right) -> depth left (Kleft(right) :: k) and eval k d = match k with | Kleft(right) :: k -> depth right (Kright(d) :: k) | Kright(dleft) :: k -> eval k (1 + max d dleft) | [] -> d in depth tree [] ;;
However the list is accessed like a stack with adding and removing only from the top. From here the C++ solution quickly follows.
type ('a, 'b) next_item = | Kleft of 'a tree | Kright of 'b
can be translated to C++ as:
enum class item_type { tree, height}; struct item { item_type type; union { Tree* root; unsigned height; }; };
The constructors for item
are just syntactic sugar. The rest of the OCaml code can be translated as:
struct Iterative_1 { static int height_aux(Tree *root, stack&lt;item&gt;&amp; items){ if(root) { item it(root-&gt;right); items.push(it); return height_aux(root-&gt;left,items); } else { return eval(items, 0); } } static int eval(stack&lt;item&gt;&amp; items, unsigned depth){ if(items.empty()){ return depth; }else{ item cur = items.top(); items.pop(); switch (cur.type) { case item_type::tree: { item next(depth); items.push(next); return height_aux(cur.root, items); } case item_type::height: { return eval(items, 1 + std::max(depth, cur.height)); } } } } static unsigned height(Tree* root){ std::stack&lt;item&gt; items; return height_aux(root,items); }
Since the recursive calls are all tail recursive we could replace each recursive call with goto
. But goto
in code is bad for your health and that of the code. Hence we replace it with loops as shown below.
static int height_aux(Tree *root, std::stack&amp;amp;amp;amp;amp;amp;amp;lt;item&amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp; items){ while (root) { item it(root-&amp;amp;amp;amp;amp;amp;amp;gt;right); items.push(it); root= root-&amp;amp;amp;amp;amp;amp;amp;gt;;left; } return eval(items, 0); } static int eval(std::stack&amp;amp;amp;amp;amp;amp;amp;lt;item&amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp; items, unsigned depth){ while (!items.empty()){ item cur = items.top(); items.pop(); switch (cur.type) { case item_type::tree: { item next(depth); items.push(next); return height_aux(cur.root, items); } case item_type::height: { depth = 1 + std::max(depth, cur.height); } } } return depth; }
Now if we inline eval
inside height_aux
a direct translation we would still require a goto
.
The variable go_on
as shown in the introduction is a work-around for goto
Additional Computation
Modifying the the iterative to compute additional properties such the number of nodes is done by replacing
depth = 1 + std::max(depth, cur.height);
with
depth = 1 + depth + cur.height;
Computing values such as the maximum value of all the nodes, or its mean or variance should now be trivial.
Personal Note
I would not have come up this solution but for the OCaml code. Thus learning a functional programming language is of great use even for writing code in languages like C++/C#/Java.
]]>Is Unix System Programming by Xavier Leroy and Didier Rémy worth your time? This blog gives a brief description of what it is, to help you decide.
The authors cover the following the topics as part of system programming:
You could develop a web server or mail server or for that matter develop any middle tier application in OCaml given that OCaml has support for all popular databases. It is not meant to be a replacement for C. It will not help you write a device driver for example.
OCaml is not popular language although a few organizations like Jane Street use it commercially. Facebook uses OCaml in some of their applications. ReasonML which is a dialect of OCaml is used the development of web and mobile applications.
Most good academic institutions teach a functional programming like OCaml, F#, Scala, Haskell, SML or a variant of Lisp. Despite this, learning a functional programming language will stand stand you in good stead. It will give you an other view of addressing programming problems. All these languages are for the most part type inferred. OCaml, F#, Scala and SML are statically type while Lisp is dynamically typed.
Such languages are usually more succinct as compared to imperative languages like C/C++/C# although a lot of functional programming features have been added to C++/C# recently. Thus learning system programming in OCaml is easier because the sample code is much smaller.
The document is helpful even if you are already familiar with Unix system programming but you want to brush up your OCaml skills or you want to write system software using OCaml. If you don’t know OCaml, then you will have some difficulty following the code. However if you already know SML or F# or Scala then Ocaml should be easy to pick up. The code used in the document is basic functional programming. You don’t have to deal with Continuation Passing Style or Functors; topics I found hard to grasp initially.
If you don’t know any functional programming language then it’s about time you learnt one.
]]>
Given an array nums of positive integers. Your task is to select some subset of
nums
, multiply each element by an integer and add all these numbers. The array is said to be good if you can obtain a sum of 1 from the array by any possible subset and multiplicand.Return True if the array is good otherwise return False.
A simple solution in Python can be as follows
from math import gcd from functools import reduce def check_good(nums): return reduce(gcd,nums) ==1
However the more interesting problem would be to generate the values k_{0}, k_{1}, … k_{n-1}, such that
nums[0]*k_{0} + nums[1]*k_{1} + ... + nums[n-1]*k_{n-1} = 1
where each k_{i} is any integer and given that the values in nums
are relatively prime. In other words, their only common factor is 1
.
Notice that we can work with any subset that is relatively prime. The simplest way to do that would be to choose the first few elements that are relatively prime.
This can be done as follows:
def get_good_array(arr): g0=gcd(arr[0],arr[1]) i =2 while i < len(arr) and not g0==1: g0 = gcd(g0,arr[i]) i+=1 return arr[:i]
Returning to our original problem let us simplify it so that we consider the case where we are dealing with just two numbers that are relatively prime. We are interested in computing k_{a} and k_{b} such that
a*k_{a} + b*k_{b} = 1
for given a
and b
that are relatively prime. Note that k_{a} and k_{b} exist if and only if a
and b
are relatively prime. The following code is one way of computing k_{a} and k_{b}.
def find_k1k2g(a,b,g=1): found = a-b==g or b-a==g ka=1 kb=1 a0 = a b0 = b if found: if a<b : ka = -1 else: kb = -1 while not found: if a0<b0 : k = b0//a ka = (k+1) a0 = ka *a kb = -kb else: k = a0//b kb = k+1 b0= kb *b ka = -ka found = a0-b0==g or b0-a0==g return (ka,kb)
The above code can be used to compute k_{a} and k_{b} in the equation
a*k_{a} + b*k_{b} = g
where g
is the greatest common divisor (GCD) of a
and b
.
Armed with this function we can now keep track of all k
‘s
multiples = [] g0=gcd(arr[0],arr[1]) multiples.append(find_k1k2g(arr[0],arr[1],g0)) array_index =2 while array_index < len(arr) and not g0==1: g1 = gcd(g0,arr[array_index]) if g1 == arr[array_index]: multiples.clear() else: multiples.append(find_k1k2g(g0,arr[array_index],g1)) g0=g1 array_index+=1
We have modified get_good_array to compute the k
‘s. The next task is to print them out in a readable form as shown below
brackets = 0 (k1,k2) = multiples.pop() while multiples) : array_index -=1 print(k2,"*", arr[array_index], "+ ", k1 , "*" , "(") (k1,k2) = multiples.pop() brackets += 1 print(k2,"*", arr[array_index-1], "+ ", k1 , "*",arr[array_index-2] ) for i in range(brackets): print(")", end="") print("")
Putting the above code snippets together we have
def prn(x,y): if x>0 : print("+", end="") print(x,"*", y ) def print_good_array(arr): multiples = [] g0=gcd(arr[0],arr[1]) multiples.append(find_k1k2g(arr[0],arr[1],g0)) i =2 while i < len(arr) and not g0==1: g1 = gcd(g0,arr[i]) if g1 == arr[i]: multiples.clear() else: multiples.append(find_k1k2g(g0,arr[i],g1)) g0=g1 i+=1 if g0 ==1 : multiplier= 1 (k1,k2) = multiples.pop() while multiples : i -=1 prn(k2*multiplier, arr[i] ) multiplier*=k1 (k1,k2) = multiples.pop() prn(k2*multiplier,arr[i-1]) prn( k1*multiplier , arr[i-2] ) else: print("Bad Array")
Thus print_good_array([77,91,175,143]) prints
-2 * 143
-41 * 175
-5330 * 91
+6396 * 77
The above answer is almost there; except we would like to have the brackets removed … an exercise left for the reader
]]>Write a function that, given an input string, locates and returns the longest sequence in the string that is a palindrome.
Every sub-string starting from the longest to the shortest needs to checked as shown below
bool is_palindrome(string const& str, size_t i,size_t n); string max_sub_palindrome(string const& str) { size_t N = str.length(); for(size_t n=N; n>0; --n) { for (size_t i=0; i+n <=N; ++i) if (is_palindrome(str,i,n)) return str.substr(i,n); } return string(); }
is_palindrome
can be computed recursively as shown below
bool is_palindrome(string const& str, size_t i,size_t n) { if (n<=1) return true; else return str[i]==str[i+n-1] && is_palindrome(str,i+1,n-2); }
The above implementation of is_palindrome
has O(n) time complexity.
Thus max_sub_palindrome
has O(N^{3}) time complexity where N is the length of the string. Notice however that is_palindrome
is can be memoised as follows:
class Search { public: Search(size_t n):N(n),arr(n*n) { } bool operator() (string const& str, size_t i,size_t n) { if (n<=1) return true; else if (Get(i,n)) return false; else if( str[i]==str[i+n-1]) { auto k = operator()(str,i+1,n-2); if (k) return k; else { Set(i,n); return k; } } else { Set(i,n); return false; } } private: bool Get (size_t i, size_t j) { return arr[i*N+j-1]; } void Set (size_t i, size_t j) { arr[i*N+j-1]=true; std::cout<<i<<","<<j<<std::endl; } std::vector<bool> arr; size_t N; };
I would like to draw your attention to Line 19 and Line 25, where we flag that the sub-string commencing at i
of length n
is not a palindrome. We make use of that fact in Line 10 so as to avoid calling the operator() recursively if the specific problem has already been visited. We could have implemented the class as a closure in any language that supports it, which is almost all languages except C/C++.
The main function is same, save for the marked line as shown below:
string max_sub_palindrome(string const& str) { size_t N = str.length(); Search is_palindrome(N); ///<---added for(size_t n=N; n>0; --n) { for (size_t i=0; i+n <=N; ++i) { if(is_palindrome(str,i,n)) return str.substr(i,n); } } return std::string(); }]]>
Marius Bancila [Bancila 2018](Chapter 8, Problem 69) describes a checksum computation problem which can be paraphrased as follows:
Let X = x_{1}x_{2}…x_{N}
where x_{i} is a decimal digit.
X is a valid number if
(Σ_{i=0}^{N} (N-i)*x_{i}) mod 10 = 0
A function to compute the checksum is shown below in C++ syntax
int checksum(const string& number) { auto index = number.length(); auto sum = 0; auto K = -1; for(auto c: number){ ++K; sum += index *(c-'0'); --index; } return sum%10; }
Loop invariant:
Here K is the index of the loop and N is the length of the string. Notice that K is redundant and included only for the purpose of the proof
However one could avoid the multiplication by using the following routine:
int my_checksum(const string& number) { auto s0 = 0; auto sum = 0; auto K = 0; for(auto c: number){ s0 += (c - '0'); sum += s0; ++K; } return sum%10; }
Loop invariant:
Once again N is the length of the string.
In case the correctness of the solution is not obvious, notice that the sum
can be computed as follows
x_{1} +
x_{1} + x_{2} +
...
x_{1} + x_{2} + ... + x_{N}
Notice that x_{1} is added N times, x_{2} is added N-1 times and so on. Thus in my_checksum, s0
computes a single row while sum
accumulates all the rows computed
Reference
[Bancila 2018] Marius Bancila “The Modern C++ Challenge” Packt Publishing Birmingham-Mumbai 2018.
The benefits of SQL-like declarative syntax for imperative programming languages like C# is [well documented](www.tutorialsteacher.com/linq/why.linq) Linq as it is known in C# has been implemented by more than one team in C++. The main advantages are
There are at least four implementations of Linq for C++:
Codeplex in turn lists other attempts:
Here I consider Berrysoft, mostly because the library implementation was easy to understand
Consider the following code:
read_lines(cin) >> where ([] (string const& str) { return str.find("include") != string::npos; }) >> write_lines(cout);
The code filters out all lines not containing the string “include”. Grep or Awk can do the same thing in one line of code. But the advantage of this code is that the data can be shaped as shown below:
struct trade{ string symbol; bool is_buy; date purchase_date; double cost; }; auto trades {read_lines(cin) >> select ([] (string const& str) { auto e{str>>split(',')>>to_vector()}; trade t; t.symbol = e[5]; t.is_buy = e[4]=="B"; istringstream{e[3]} >> parse("%d/%m/%Y", t.purchase_date); t.cost = strtod(e[8].c_str((), nullptr); return t; }) >> to_vector()};
At this point we have all the trades stored in a container and from here on we get the full power of C++. As an aside [Howard Hinant’s](https://github.com/HowardHinnant/date) date library is used in the above code.
]]>Abstract
In considering how to print a multiway tree in heirarchical fashion, this blog shows that there are many ways to represent a multiway tree in a data structure. A node with a pointer to a list of child nodes is not always the best.
Source Code: https://github.com/theSundayProgrammer/heirarchy_CPP
Problem
Consider a table of the of following form:
________________________
|parent_id|item_id|info|
________________________
where item_id is unique to every row and parent_id matches with an item_id of some row except for a special row called the root which has a special parent_id, say zero, that is not present as an item_id. It is required to print this table in an heirachical fashion as for example
Root Child1 Subchild1 Subchild2 ... SubchildN Child2 Subchild21 Subchild22
The first solution is to convert the given linear data into a multiway tree and traverse the data in a pre-order fashion. This can be done by picking the root node and traversing the tree to pick all its immediate children and then recursively the children of the children, using a breadth-first or depth-first algorithm. Another way to do it would be to use a map (known as intermediate map henceforth) from the parent_id
to an array of children. This can then be used to generate a multiway tree.
struct raw_child { int id; content name; int parent; }; struct Child { Child(content const& name_): name(name_){ } content name; std::vector<Child> children; }; std::map<int, vector<Data>> list_children; void generate_map(raw_child const& child) { list_children[child.parent].push_back({child.id,child.name}); } Data& get_root(int k) { return list_children[k][0]; } Child generate_tree(Data const & root) { auto item = list_children.find(root.id); Child parent(root.name); if (item != list_children.end()) { auto& subs = item->second; for (auto& ch : subs) { parent.children.push_back(generate_tree(ch)); } } return parent; }
Another way to represent the intermediate map is using a multi-map as in C++ multimap or Ocaml Hashtbl.
Notice that since the sole purpose of the tree is print the data in a heirarchical fashion, it is possible to print the data using the same traversal as in generating a tree. Hence there is no need to generate the tree.
void print_tree(Data const & root, int tab_count) { auto item = list_children.find(root.id); Child parent(root.name); if (item != list_children.end()) { auto& subs = item->second; for (auto& sub : subs) print_tree(sub, tab_count+1); } return parent; }
Taking a cue from Chartier as quoted above I considered other ways to address the main problem which is to print the array data in a heirachical fashion. The brute force solution would to be start with the root and then traverse the array to print all its children and all their children recursively. Notice from the code below that if n is the number of rows the time complexity is O(n^{2}) in terms of comparisons because each non-leaf item (one which is parent of at least one other item) takes n comparisons to print all its immediate children and each leaf node (one that is not a parent of any other) takes n comparisons to determine it is a leaf node.
void print_tree( raw_child const &root, int tab_count) { int k; for (int i = 0; i < tab_count; ++i) std::cout << " "; std::cout << root.name << std::endl; auto child = std::find_if(raw_children.begin(), raw_children.end(), [&](raw_child const &r) { return r.parent == root.id; }); while (child != raw_children.end()) { print_tree(*child, tab_count + 1); child = std::find_if(child+1, raw_children.end(), [&](raw_child const &r) { return r.parent == root.id; }); } }
To reduce that time complexity we could sort the array based on parent_id. This would reduce the number of comparisons to at most O(log(n)). Hence including the sorting this would take O(n.log(n)). In other words we have used a sorted array to represent a multiway tree as shown below
void print_tree( raw_child const &root, int tab_count) { int k; for (int i = 0; i < tab_count; ++i) std::cout << " "; std::cout << root.name << std::endl; auto child = std::lower_bound(std::begin(raw_children), std::end(raw_children),root, [](raw_child const& a, raw_child const& val){ return a.parent parent == root.id) { print_tree(*child, tab_count + 1); ++child; } }
Conclusion
There is more than one way to accomplish a programming task. Thinking of different ways helps in improving an existing solution.
Write a function that, prints on the console all the possible permutations of a given string.
and provides a recursive version of the solution as follows:
void next_permutation(std::string str, std::string perm) { if (str.empty()) std::cout << perm << std::endl; else { for (size_t i = 0; i< str.size(); ++i) { next_permutation(str.substr(1), perm + str[0]); std::rotate(std::begin(str), std::begin(str) + 1, std::end(str)); } } } void print_permutations_recursive(std::string str) { next_permutation(str, ""); }
A better solution would be as follows
void next_permutation(std::string& str, size_t n) { if (n==1) std::cout << str << std::endl; else { for (size_t i = 0; i<n; ++i) { next_permutation(str,n-1); std::rotate( std::end(str)-n , std::end(str)-n+1, std::end(str)); } } } void print_permutations_recursive(std::string str) { if(!str.empty()) next_permutation(str, str.length()); }
This avoids string copy over recursive calls. More importantly the second parameter
has a meaning in that it is the length of the suffix that needs to be permuted.
The other thing to notice is that rotate
is O(n) which can be reduced to O(1) by swapping as in
for (size_t i = 0; i < n; ++i) { std::swap(*(str.end()-n), *(str.end()-n+i)); next_permutation(str,n-1); std::swap(*(str.end()-n), *(str.end()-n+i)); }
Reference
[Bancila 2018] Marius Bancila "The Modern C++ Challenge" Packt Publishing Birmingham-Mumbai 2018.
So why would one create a text file and get it compiled rather than thus use Word.
Just like word there are templates for most common purposes such as Resumes, Invoices, APA style academic documents etc.
There are other options to Latex which are also free.
Given two positive integers A and B compute the quotient and remainder without using multiplication. This is an old problem except, in optimising the algorithm we derive the long division method taught in primary school.
Problem: Given A and B, where A>0
and B>0
compute q and r such that:
A = B*q +r
where q≥0
and r≥0
using only addition and subtraction. This is a fairly simple algorithm as shown below:
def divisor(A,B): q = 0 r = A #loop invariant : A = q*B + r while (r >= B): q,r = q+1, r-B return q,r
The time complexity is O(A/B). If A is say one million and B is 3, then the loop will executed 333,333 times. How can we reduce the number of iterations? We could reduce it by half if we deduct B twice as shown below
def divisor(A,B): q = 0 r = A #loop invariant : A = q*B + r twiceB = B + B while (r >= B): if (r >= twiceB) : q,r = q+2, r - twiceB else : q,r = q+1, r-B return q,r
Now, why do we want to reduce only twice? Why not four times or eight or more? If we allow multiplication or division by the radix then we can use the following procedure. Multiplication of a number by the radix is trivial because it means moving the digits of number left or right.
def divisor(A,B): q,r=0,A q0,r0=1,B radix=2 #loop invariant r0 = B * q0 while r0*radix ≤ A: q0,r0=radix*q0, radix*r0 #loop invariant : A = q*B + r while r≥B: #loop invariant : A = q*B + r while r0≤r: q,r = q+q0, r-r0 q0,r0 = q0/radix, r0/radix return q,r
Notice that the above algorithm works even if the radix is ten, or in other words all numbers are represented in decimal. In Line 6, we are pushing B to the left until it is just greater than A. q0
keeps track of how much B is being shifted left. Notice that if the radix were two the while
loop in Line 11 is a conditional statement. To prove that the loop invariant holds note that
r0 = B * q0
Hence
(q+q0)*B + r-r0 = q*B + r +(q0*B -r0) = q*B + r = A (QED)
Thus dear reader you now have the algorithm that was taught to you in primary school in Python-esque code.
Time Complexity
The while
loop commencing at Line 9 computes the most significant digit or bit of the quotient at the first iteration.;the next most significant bit at the next iteration and so on. Hence the number of iterations can be at most log(A/B). The inner loop at Line 11 is executed at most radix
times. Hence the time complexity is O(log(A/B)).
]]>