Generating all binary trees of N nodes in lexigraphical order - algorithm

I was just curious if anyone has an algorithm for how to generate binary trees of N nodes in lexigraphical order.
The very first binary tree would be a right chain of length N. The last tree would be a left chain of length N. I would like to know how to generate the trees in between the first binary tree and last binary tree in lexigraphical order.
A tree with 4 nodes would have 14 binary trees.
A tree with 3 nodes would have 5 binary trees.
etc.
EDIT:
So, when you predorder traverse a tree, if you hit a non-null node you output a 1, if you hit a null output a 0. So the tree is ordered from 1,2,3,...N. A tree of node 5 would have a right chain of 1,2,3,4,5 in this order. I was thinking theoreticially this could work: If I just take the lowest numbered leaf node and reverse preorder traverse one position and move this node to that position. If this node was originally a child of its node-1, and after reverse preorder traversing this node is no longer a child of node-1, than I shift all LEAF nodes less than this node to the best possible preorder position (which should probably be the most right branch).

I won't give you a direct solution. But I will give an solution here for a similar problem: Given n, generate all structurally unique BST's (binary search trees) that store values 1...n.
I think it is not hard for you to modify my solution a little bit to solve your problem.
public class Solution {
public List<TreeNode> generateTrees(int n) {
return helper(1, n);
}
private List<TreeNode> helper(int start, int end) {
List<TreeNode> result = new ArrayList<TreeNode>();
if (start > end) {
result.add(null);
return result;
}
// You just need to understand how below for loop works.
for (int i = start; i <= end; i++) {
List<TreeNode> left = helper(start, i - 1);
List<TreeNode> right = helper(i + 1, end);
for (TreeNode l : left) {
for (TreeNode r : right) {
TreeNode root = new TreeNode(i);
root.left = l;
root.right = r;
result.add(root);
}
}
}
return result;
}
}
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; left = null; right = null; }
}
The solution is pretty straightforward using Dynamic Programming.

Related

Split a Binary Tree using specific methods

Given a binary tree, I have to return a tree containing all elements that smaller than k, greater than k and a tree containing only one element - k.
Allowed methods to use:
remove node - O(n)
insert - O(n)
find - O(n)
find min - O(n)
I'm assuming these methods complexity, because in the exercise it's not written that tree is balanced.
Required complexity - O(n)
Original tree have to maintain its structure.
I'm completely stuck. Any help is much appreciated!
Given tree is Binary search tree as well as outputs should be binary search trees.
I see no way to design a O(n) algorithm with the given blackbox functions and their time complexities, given that they could only be called a (maximum) constant number of times (like 3 times) to stay within the O(n) constraint.
But if it is allowed to access and create BSTs with basic, standard node manipulations (traversing via left or right child, setting the left or right child to a given subtree), then you could do the following:
Create three new empty BSTs that will be populated and returned. Name them left, mid, and right, where the first one will have all values less than k, the second one will have at the most one node (with value k), and the final one will have all the rest.
While populating left and right, maintain references to the nodes that are closest to value k: in left that will be the node with the greatest value, and in right the node with the least value.
Follow these steps:
Apply the usual binary search to walk from the root towards the node with value k
While doing this: whenever you choose the left child of a node, the node itself and its right subtree then belong in right. However, the left child should at this moment not be included, so create a new node that copies the current node, but without its left child. Maintain a reference to the node with the least value in right, as that is the node that may get a left new subtree when this step occurs more than once.
Do the similar thing for when you choose the right child of a node.
When the node with k is found, the algorithm can add its left subtree to left and the right subtree to right, and create the single-node tree with value k.
Time complexity
The search towards the node with value k could take O(n) in the worst case, as the BST is not given to be balanced. All the other actions (adding a subtree to a specific node in one of the new BSTs) run in constant time, so in total they are executed O(n) times in the worst case.
If the given BST is balanced (not necessarily perfectly, but like with AVL rules), then the algorithm runs in O(logn) time. However, the output BSTs may not be as balanced, and may violate AVL rules so that rotations would be needed.
Example Implementation
Here is an implementation in JavaScript. When you run this snippet, a test case will run one a BST that has nodes with values 0..19 (inserted in random order) and k=10. The output will iterate the three created BSTs in in-order, so to verify that they output 0..9, 10, and 11..19 respectively:
class Node {
constructor(value, left=null, right=null) {
this.value = value;
this.left = left;
this.right = right;
}
insert(value) { // Insert as a leaf, maintaining the BST property
if (value < this.value) {
if (this.left !== null) {
return this.left.insert(value);
}
this.left = new Node(value);
return this.left;
} else {
if (this.right !== null) {
return this.right.insert(value);
}
this.right = new Node(value);
return this.right;
}
}
// Utility function to iterate the BST values in in-order sequence
* [Symbol.iterator]() {
if (this.left !== null) yield * this.left;
yield this.value;
if (this.right !== null) yield * this.right;
}
}
// The main algorithm
function splitInThree(root, k) {
let node = root;
// Variables for the roots of the trees to return:
let left = null;
let mid = null;
let right = null;
// Reference to the nodes that are lexically closest to k:
let next = null;
let prev = null;
while (node !== null) {
// Create a copy of the current node
newNode = new Node(node.value);
if (k < node.value) {
// All nodes at the right go with it, but it gets no left child at this stage
newNode.right = node.right;
// Merge this with the tree we are creating for nodes with value > k
if (right === null) {
right = newNode;
} else {
next.left = newNode;
}
next = newNode;
node = node.left;
} else if (k > node.value) {
// All nodes at the left go with it, but it gets no right child at this stage
newNode.left = node.left;
// Merge this with the tree we are creating for nodes with value < k
if (left === null) {
left = newNode;
} else {
prev.right = newNode;
}
prev = newNode;
node = node.right;
} else {
// Create the root-only tree for k
mid = newNode;
// The left subtree belongs in the left tree
if (left === null) {
left = node.left;
} else {
prev.right = node.left;
}
// ...and the right subtree in the right tree
if (right === null) {
right = node.right;
} else {
next.left = node.right;
}
// All nodes have been allocated to a target tree
break;
}
}
// return the three new trees:
return [left, mid, right];
}
// === Test code for the algorithm ===
// Utility function
function shuffled(a) {
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
// Create a shuffled array of the integers 0...19
let arr = shuffled([...Array(20).keys()]);
// Insert these values into a new BST:
let root = new Node(arr.pop());
for (let val of arr) root.insert(val);
// Apply the algorithm with k=10
let [left, mid, right] = splitInThree(root, 10);
// Print out the values from the three BSTs:
console.log(...left); // 0..9
console.log(...mid); // 10
console.log(...right); // 11..19
Essentially, your goal is to create a valid BST where k is the root node; in this case, the left subtree is a BST containing all elements less than k, and the right subtree is a BST containing all elements greater than k.
This can be achieved by a series of tree rotations:
First, do an O(n) search for the node of value k, building a stack of its ancestors up to the root node.
While there are any remaining ancestors, pop one from the stack, and perform a tree rotation making k the parent of this ancestor.
Each rotation takes O(1) time, so this algorithm terminates in O(n) time, because there are at most O(n) ancestors. In a balanced tree, the algorithm takes O(log n) time, although the result is not a balanced tree.
In your question you write that "insert" and "remove" operations take O(n) time, but that this is your assumption, i.e. it is not stated in the question that these operations take O(n) time. If you are operating only nodes you already have pointers to, then basic operations take O(1) time.
If it is required not to destroy the original tree, then you can begin by making a copy of it in O(n) time.
I really don't see a simple and efficient way to split with the operations that you mention. But I think that achieving a very efficient split is relatively easy.
If the tree were balanced, then you can perform your split in O(log n) if you define a special operation called join exclusive. Let me first define join_ex() as the operation in question:
Node * join_exclusive(Node *& ts, Node *& tg)
{
if (ts == NULL)
return tg;
if (tg == NULL)
return ts;
tg=.llink) = join_exclusive(ts->rlink, tg->llink);
ts->rlink = tg;
Node * ret_val = ts;
ts = tg = NULL; // empty the trees
return ret_val;
}
join_ex() assumes that you want to build a new tree from two BST ts and tr such that every key in ts is less than everyone in tr.
If you have two exclusive trees T< and T>:
Then join_ex() can be seen as follows:
Note that if you take any node for any BST, then its subtrees meet this condition; every key in the left subtree is less than everyone in the right one. You can design a nice deletion algorithm based on join_ex().
Now we are ready for the split operation:
void split_key_rec(Node * root, const key_type & key, Node *& ts, Node *& tg)
{
if (root == NULL)
{
ts = tg = NULL;
return;
}
if (key < root->key)
{
split_key_rec(root->llink, key, ts, root->llink);
tg = root;
}
else
{
split_key_rec(root->rlink, key, root->rlink, tg)
ts = root;
}
}
If you set root as T in this figure
Then a pictorial representation of split can be seen thus:
split_key_rec() splits the tree into two trees ts and tg according to a key k. At the end of the operation, ts contains a BST with keys less than k and tg is a BST with keys greater or equal than k.
Now, to complete your requirement, you call split_key_rec(t, k, ts, tg) and you get in ts a BST with all the keys less than k. Almost symmetrically, you get in tg a BST with all the keys greater or equal than k. So, the last thing is to verify if the root of tg is k and, if this is the case, you unlink, and you get your result in ts, k, and tg' (tg' is the tree without k).
If k is in the original tree, then the root of tg will be k, and tg won't have left subtree.

Finding smallest (or largest) k elements in a given balanced binary search tree

Given a balanced binary search tree with integer nodes, I need to write an algorithm to find the smallest k elements and store them in a linked list or array. The tricky part is, it is required such algorithm runs in O(k+log(n)), where n is the number of elements in the tree. I only have an algorithm that runs O(k*log(n)), which uses the rank function. So my question is how to achieve the required performance?
I've written a code doing such algorithm but I don't know if it is running at O(k+log(n)):
(The size function is the number of nodes with the given subtree.)
// find k smallest elements in the tree
public Iterable<Key> kSmallest(int k) {
LinkedList<Key> keys = new LinkedList<Key>();
kSmallest(k, root, keys);
return keys;
}
// find k smallest elements in the subtree given by node and add them to keys
private void kSmallest(int k, Node node, LinkedList<Key> keys) {
if (k <= 0 || node == null) return;
if (node.left != null) {
if (size(node.left) >= k) kSmallest(k, node.left, keys);
else {
keys.add(node.key);
kSmallest(k - 1, node.left, keys);
kSmallest(k - 1 - size(node.left), node.right, keys);
}
}
else {
keys.add(node.key);
kSmallest(k - 1, node.right, keys);
}
}
Just have to to a inorder traversal and stop when you have gone through k nodes.
this would run in O(k+log(n)) time.
code:
int k = nodesRequired;
int A[] = new int[k];
int number_of_nodes=0;
void traverse_tree(tree *l){
if (number_of_nodes<k) {
traverse_tree(l->left);
process_item(l->item);
traverse_tree(l->right);
}
}
void process_item(item){
A.push(item);
++number_of_nodes;
}

Finding the left-most child for every node in a tree in linear time?

A paper I am reading claims that
It is easy to see that there is a linear time algorithm to compute the function l()
where l() gives the left-most child (both input and output are in postorder traversal of the tree). However, I can only think of a naive O(n^2) implementation where n is the number of nodes in the tree.
As an example, consider the following tree:
a
/ \
c b
In postorder traversal, the tree is c b a. The corresponding function l() should give c b c.
Here is my implementation in O(n^2) time.
public Object[] computeFunctionL(){
ArrayList<String> l= new ArrayList<String>();
l= l(this, l);
return l.toArray();
}
private ArrayList<String> l(Node currentRoot, ArrayList<String> l){
for (int i= 0; i < currentRoot.children.size(); i++){
l= l(currentRoot.children.get(i), l);
}
while(currentRoot.children.size() != 0){
currentRoot= currentRoot.children.get(0);
}
l.add(currentRoot.label);
return l;
}
The tree is made as:
public class Node {
private String label;
private ArrayList<Node> children= new ArrayList<Node>();
...
There is a simple recursive algorithm you can use that can compute this information in O(1) time per node. Since there are n total nodes, this would run in O(n) total time.
The basic idea is the following recursive insight:
For any node n with no left child, l(n) = n.
Otherwise, if n has left child L, then l(n) = l(L).
This gives rise to this recursive algorithm, which annotates each node with its l value:
function computeL(node n) {
if n is null, return.
computeL(n.left)
computeL(n.right)
if n has no left child:
set n.l = n
else
set n.l = n.left.l
Hope this helps!
You can find l() for the entire tree in less than O(n^2) time. The idea is to traverse the tree in order, maintaing a stack of the nodes you've visited while traversing the left branch. When you get to a leaf, that is the leftmost node for the entire branch.
Here's an example:
class BTreeNode
{
public readonly int Value;
public BTreeNode LeftChild { get; private set; }
public BTreeNode RightChild { get; private set; }
}
void ShowLeftmost(BTreeNode node, Stack<int> stack)
{
if (node.LeftChild == null)
{
// this is the leftmost node of every node on the stack
while (stack.Count > 0)
{
var v = stack.Pop();
Console.WriteLine("Leftmost node of {0} is {1}", v, node.Value);
}
}
else
{
// push this value onto the stack so that
// we can add its leftmost node when we find it.
stack.Push(node.Value);
ShowLeftmost(node.LeftChild, stack);
}
if (node.RightChild != null)
ShowLeftmost(node.RightChild, stack);
}
The complexity is clearly not O(n^2). Rather, it's O(n).
It takes O(n) to traverse the tree. No node is placed on the stack more than once. The worst case for this algorithm is a tree that contains all left nodes. In that case it's O(n) to traverse the tree and O(n) to enumerate the stack. The best case is a tree that contains all right nodes, in which case there is never any stack to enumerate.
So O(n) time complexity, with O(n) worst case extra space for the stack.
Take a look at section 3.1:
3.1. Notation. Let T[i] be the ith node in the tree according to the left-to-right
postorder numbering, l(i) is the number of the leftmost leaf descendant of the subtree
rooted at T[i].
Given that sentence about notation, I would assume that the function l() is referring to finding a single node in linear time.
There may be a more elegant (better than O(n^2)) way of finding l() for an entire tree but I think it's referring to a single node.

Generating all possible topologies in a full binary tree having n nodes

I want to create all possible topologies of a full binary tree which must have exactly n+1 leaf nodes and n internal nodes.
I want to create it using recursion and tree must be simple binary tree not a binary search tree or BST.
Kindly suggest algorithm to achieve this task.
example: with 4 leaf nodes and 3 internal nodes.
N N N
/ \ / \ /\
N N N N N N
/\ /\ /\ /\
N N N N N N N N
/ \ /\
N N N N
PS: There is a simlar thread .It will be helpful If anybody can elaborate the tree generation algorithm suggested by coproc in this thread.
Thanks in advance.
Here is the code for generating all possibles topologies for given n. Total Number of nodes (internal + leaf nodes) in a full binary tree is odd.
If a tree is full binary tree, then it's left and right sub trees are also full binary trees i.e both left and right sub trees have odd number of nodes.
For a given n, We generate all combinations of full binary tree like this
First Iteration: 1 Node on left hand side, 1 root, n-2 on right hand side.
Second Iteration: 3 Nodes on left hand side, 1 root, n-4 on right hand side.
Third Iteration: 5 Nodes on left hand side, 1 root, n-6 on right hand side.
.
.
.
Last Iteration: n-2 Nodes on left hand side, 1 root, 1 on right hand side
In each iteration, we find all possible left trees and right trees. If L full trees are possible on left hand side, R full trees are possible on right hand side - then total number of trees is L*R
public void createAllTopologies(int n){
if(n%2 == 0) return;
Map<Integer, List<Node>> topologies = new HashMap<Integer, List<Node>>();
topologies.put(1, new ArrayList<Node>());
topologies.get(1).add(new Node(1));
for(int i=3;i<=n;i+=2){
List<Node> list = new ArrayList<Node>();
for(int j=1;j<i;j+=2){
List<Node> left = topologies.get(j);
List<Node> right = topologies.get(i-j-1);
list.addAll(generateAllCombinations(left,right));
}
topologies.put(i, list);
}
List<Node> result = topologies.get(n);
for(int i=0;i<result.size();i++){
printTree(result.get(i),0);
System.out.println("-----------------------------");
}
}
private List<Node> generateAllCombinations(List<Node> left, List<Node> right) {
List<Node> list = new ArrayList<Node>();
for(int i=0;i<left.size();i++){
for(int j=0;j<right.size();j++){
Node nNode = new Node(1);
nNode.left = left.get(i).clone();
nNode.right = right.get(j).clone();
list.add(nNode);
}
}
return list;
}
/* This prints tree from left to right fashion i.e
root at left,
leftNode at bottom,
rightNode at top
*/
protected void printTree(Node nNode,int pos){
if (nNode==null) {
for(int i=0;i<pos;i++) System.out.print("\t");
System.out.println("*");
return;
}
printTree(nNode.right,pos+1);
for(int i=0;i<pos;i++) System.out.print("\t");
System.out.println(nNode.data);
printTree(nNode.left,pos+1);
}
Please refer to complete code here - http://ideone.com/Wz2Jhm
I am using recursion here. This code can be improved by using dynamic programming. I hope this helps. We start by one node in the left, one node as root and N-i-1 nodes in the right. Then, we move nodes from the right to left as pairs.
import java.util.ArrayList;
import java.util.List;
public class NumberOfFullBTrees {
public static void main(String[] args) {
int N = 5;
NumberOfFullBTrees numberOfFullBTrees = new NumberOfFullBTrees();
List<TreeNode> result = numberOfFullBTrees.allPossibleFBT(N);
}
/**
* Builds all possible full binary trees. We start by 1 node in left, 1 note at root and n-2 node in right.
* We move the nodes in pairs from right to left. This method uses recursion. This method can be improved by
* using dynamic programming.
*
* #param N The number of nodes
* #return The possible full binary trees with N nodes as a list
*/
public List<TreeNode> allPossibleFBT(int N) {
List<TreeNode> result = new ArrayList<>();
if (N % 2 == 0) {
return result;
}
if (N == 1) {
result.add(new TreeNode(0));
return result;
}
for (int i = 1; i < N; i += 2) {
List<TreeNode> lefts = allPossibleFBT(i);
List<TreeNode> rights = allPossibleFBT(N - i - 1);
for (TreeNode l : lefts) {
for (TreeNode r : rights) {
TreeNode root = new TreeNode(0);
root.left = l;
root.right = r;
result.add(root);
}
}
}
return result;
}
}

balanced binary tree visit with a twist

Looking for an in-place O(N) algorithm which prints the node pair(while traversing the tree) like below for a given balanced binary tree:
a
b c
d e f g
Output: bc, de, ef, fg
Where 'a' is the root node, 'b' the left child, 'c' the right, etc.
Please note the pair 'ef' in the output.
Additional info based on comments below:
'node pair' is each adjacent pair at each level
each node can have 'parent' pointer/reference in addition to 'left' and 'right'
If we were to relax O(N) and in-place, are there more simple solutions (both recursive and iterative)?
If this tree is stored in an array, it can be rearranged to be "level continuous" (the first element is the root, the next two its children, the next four their children, etc), and the problem is trivial.
If it is stored in another way, it becomes problematic. You could try a breadth-first traversal, but that can consume O(n) memory.
Well I guess you can create an O(n log n) time algorithm by storing the current level and the path to the current element (represented as a binary number), and only storing the last visited element to be able to create pairs. Only O(1 + log n) memory. -> This might actually be an O(n) algorithm with backtracking (see below).
I know there is an easy algorithm that visits all nodes in order in O(n), so there might be a trick to visit "sister" nodes in order in O(n) time. O(n log n) time is guaranteed tho, you could just stop at a given level.
There is a trivial O(n log n) algorithm as well, you just have to filter the nodes for a given level, increasing the level for the next loop.
Edit:
Okay, I created a solution that runs in O(n) with O(1) memory (two machine word sized variables to keep track of the current and maximal level /which is technically O(log log n) memory, but let's gloss over that/ and a few Nodes), but it requires that all Nodes contain a pointer to their parent. With this special structure it is possible to do an inorder traversal without an O(n log n) stack, only using two Nodes for stepping either left, up or right. You stop at a particular maximum level and never go below it. You keep track of the actual and the maximum level, and the last Node you encountered on the maximum level. Obviously you can print out such pairs if you encounter the next at the max level. You increase the maximum level each time you realize there is no more on that level.
Starting from the root Node in an n-1 node binary tree, this amounts to 1 + 3 + 7 + 15 + ... + n - 1 operations. This is 2 + 4 + 8 + 16 + ... + n - log2n = 2n - log2n = O(n) operations.
Without the special Node* parent members, this algorithm is only possible with O(log n) memory due to the stack needed for the in-order traversal.
Assuming you have the following structure as your tree:
struct Node
{
Node *left;
Node *right;
int value;
};
You can print out all pairs in three passes modifying the tree in place. The idea is to link nodes at the same depth together with their right pointer. You traverse down by following left pointers. We also maintain a count of expected nodes for each depth since we don't null terminate the list for each depth. Then, we unzip to restore the tree to its original configuration.
The beauty of this is the zip_down function; it "zips" together two subtrees such that the right branch of the left subtree points to the left branch of the right subtree. If you do this for every subtree, you can iterate over each depth by following the right pointer.
struct Node
{
Node *left;
Node *right;
int value;
};
void zip_down(Node *left, Node *right)
{
if (left && right)
{
zip_down(left->right, right->left);
left->right= right;
}
}
void zip(Node *left, Node *right)
{
if (left && right)
{
zip(left->left, left->right);
zip_down(left, right);
zip(right->left, right->right);
}
}
void print_pairs(const Node * const node, int depth)
{
int count= 1 << depth;
for (const Node *node_iter= node; count > 1; node_iter= node_iter->right, --count)
{
printf("(%c, %c) ", node_iter->value, node_iter->right->value);
}
if (node->left)
{
print_pairs(node->left, depth + 1);
}
}
void generate_tree(int depth, Node *node, char *next)
{
if (depth>0)
{
(node->left= new Node)->value= (*next)++;
(node->right= new Node)->value= (*next)++;
generate_tree(depth - 1, node->left, next);
generate_tree(depth - 1, node->right, next);
}
else
{
node->left= NULL;
node->right= NULL;
}
}
void print_tree(const Node * const node)
{
if (node)
{
printf("%c", node->value);
print_tree(node->left);
print_tree(node->right);
}
}
void unzip(Node * const node)
{
if (node->left && node->right)
{
node->right= node->left->right;
assert(node->right->value - node->left->value == 1);
unzip(node->left);
unzip(node->right);
}
else
{
assert(node->left==NULL);
node->right= NULL;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
char value_generator= 'a';
Node root;
root.value= value_generator++;
generate_tree(2, &root, &value_generator);
print_tree(&root);
printf("\n");
zip(root.left, root.right);
print_pairs(&root, 0);
printf("\n");
unzip(&root);
print_tree(&root);
printf("\n");
return 0;
}
EDIT4: in-place, O(n) time, O(log n) stack space.

Resources