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

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;
}
}

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.

Kth largest element using in-order traversal without knowing the height of the binary search tree

Can we find the kth largest element using inorder traversal without knowing the height of the binary search tree?
Or is there a way where we make a new pattern of traversal like "RIGHT ROOT LEFT"
Can we find the kth largest element using inorder traversal without knowing the height of the binary search tree?
Yes we can.
We can do that using some extra space.
We do not necessarily need to do RIGHT-ROOT-LEFT to find out kth largest element (Although doing so would avoid usage of extra space).
There are several approaches.
The most basic one is to have a queue.
Whenever you are traversing inorder-ly, keep inserting the values in the queue.
Needless to say, as it is a binary search tree, the queue will be sorted.
Thus the kth largest element is at queue.size() - 1 - k index. (Assuming that 0th largrst is the maximum element, 1st largest is 2nd maximum and so on)
This approach would require O(n) extra space regardless of k
To optimize the space used, we can use the information about k
Note that we only need element at (queue.size() - 1 - k)th index. Thus
we can have a queue of size (k+1). Before inserting an element, we will check if the queue has more than k element, if it has, we would remove one element from front as we do not require it.
After the traversal is done, the kth largest element would be at the front of the queue.
Here is the java implementation of both the approaches :
import java.util.LinkedList;
import java.util.Queue;
class Node {
int data;
Node left;
Node right;
static Queue<Integer> efficient = new LinkedList<>();
static Queue<Integer> complete = new LinkedList<>();
Node(int n) {
this.data = n;
this.left = null;
this.right = null;
}
public static void inorder(Node node, int k) {
if (node == null) {
return;
}
inorder(node.left, k);
if (efficient.size() > k) {
efficient.poll();
}
efficient.add(node.data);
complete.add(node.data);
System.out.println(efficient.toString());
inorder(node.right, k);
}
public static void main(String[] args) {
Node root = new Node(7);
root.left = new Node(4);
root.left.left = new Node(1);
root.left.right = new Node(5);
root.left.right.right = new Node(6);
root.right = new Node(9);
int k = 2;
inorder(root, k);
System.out.println("Efficient queue size : " + efficient.size() + " " + efficient.peek());
System.out.println("Full queue size : " + complete.size() + " " + complete.toArray()[complete.size() - 1 - k]);
}
}
Run this and you will know how efficient queue grows.
Please note that here, k should be less than the number of nodes in the tree. If it is not, then the answer would be the smallest element.
Other approaches uses a heap for more general solution. In such cases the tree is not required to be a binary search tree.
What about this:
let x be the node corresponding to the minimum element of the tree (e.g. x = T.root; while (x->right != NULL) { x = x->right; })
Now repeat x = x.predecessor() k-1 times (obviously, take care of edge case)
return x (you've found the k-th largest element in the tree)
Implementing predecessor and successor methods on a BST isn't hard, and it's easy when nodes have an additional pointer to parent node.
Are you talking about a simple binary tree or any tree like AVL tree?
If I understand correctly, you don't need to know the height at all...
Inorder traversal - RIGHT ROOT LEFT - is supposed to go from the highest value to the lowest.
Each time you enter the function, you may increase a static variable(or send another argument to the function) - until you get to K.
You may also maintain a degree tree, and know directly where to go through that tree.

Generating all binary trees of N nodes in lexigraphical order

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.

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;
}

Sorting the elements in Binary trees

Here is a question I was recently asked in an interview. A binary tree is given with a condition that each left child is 1 smaller than root and right child is 1 larger. Here is a sample tree
Sort it in O(1) and O(n) time complexity.
Here are the approaches I suggested:
Use a count to maintain the count of each elements and then return once entire traversal is done O(n) time and O(n) space complexity.
Use run length encoding. Form a chain when the element is repeated with the number as the key and count as the value. Requires space for count only when no is repeated and so requires no extra space apart from array but the time complexity will be O(n log n) since we have to traverse the array to see if it is there.
Finally I suggested breadth first traversal. We require O(log n) space for queue and O(n) time complexity (Assuming insertion is O(1) linked list).
What are your approaches?
Fix some Leaf node of the given tree as NewHead .
Write a function Pop() remove some node from the given tree ..!
Write pop node such that you will remove it only when it is ! equal to NewHead .
So pop value from tree , insert it to the New binary search tree with New Head as Head node .
So u will remove an element from tree add it to new search tree .
Until tree head point NewHead .
So all you elements are now in binary search tree pointing to the New head , which will be
obviously in sorted order .
This way promise you a sorting in O(NlogN) .
Analysis
Given your definition of a binary-tree we have the following,
Each Node have a Parent, L-child, and R-child .. where:
L < N
R > N
P > N
We also can do this:
L < N AND R > N => L < N < R => L < R
L < N AND P > N => L < N < P => L < P
R > N AND P > N => N < MIN(P,R)
N < MIN(P,R) AND L < N => L < N < MIN(P,R)
And now let's try expanding it, N.L = Left-child of N:
N.L < N
N.R > N
N.P > N
N.L.L < N.L < MIN(N, N.L.R)
N.L.R > N.L > N.L.L
N.R.L < N.R < MIN(N, N.R.R)
N.R.R > N.R > N.R.L
IF N IS N.P LEFT-CHILD: N < N.P < MIN(N.P.P, N.P.R)
IF N IS N.P RIGHT-CHILD: N > N.P.R
Proposed Solution
This problem seems complex, but my solution will be using merge sort after inserting values in a traversal order Left-Right-Parent which will help the merge sort to get a time complexity somewhere between its average and optimal case, but with a small trick using the comparisons I've done above.
First we collect tree nodes in a list, using Left-Right-Parent traversal, given the fact that: N.L < N < MIN(N.R, N.P) and with giving the parent a higher weight assuming O(N.R) <= O(N.P) with values decrease linearly when we go left-side each time .. > N.R.R > N.R > N > N.L > N.L.L > ...
After collecting the tree nodes in that traversal order, the list have some sorted chunks, which will help the merge sort that we'll use next.
This solution works in: Time = O(n log n + n), Space = O(n)
Here is the algorithm written in Java (not tested):
private class Node Comparable<Node>
{
public Node R;
public Node L;
public int value;
public Node (Node L, int val, Node R)
{
this.L = L;
this.value = val;
this.R = R;
}
#Override
public int compareTo(Node other)
{
return ((other != null) ? (this.value-other.value) : 0);
}
}
class Main
{
private static Node head;
private static void recursive_collect (Node n, ArrayList<Node> list)
{
if (n == null) return;
if (n.left != null) recursive_collect (n.L, list);
if (n.right != null) recursive_collect (n.R, list);
list.add(n.value);
}
public static ArrayList<Node> collect ()
{
ArrayList<Node> list = new ArrayList<Node>();
recursive_collect (head, list);
return list;
}
// sorting the tree: O(n log n + n)
public static ArrayList<Node> sortTree ()
{
// Collecting nodes: O(n)
ArrayList<Node> list = collect();
// Merge Sort: O(n log n)
Collections.sort(list);
return list;
}
// The example in the picture you provided
public static void createTestTree ()
{
Node left1 = new Node (new Node(null,-2,null), -1, new Node(null,0,null));
Node left2 = new Node (new Node(null,-1,null), 0, new Node(null,1,null));
Node right = new Node (left2, 1, new Node(null,2,null));
head = new Node (left1, 0, right);
}
// test
public static void main(String [] args)
{
createTestTree ();
ArrayList<Node> list = sortTree ();
for (Node n : list)
{
System.out.println(n.value);
}
}
}
I guess , you are looking for DFS(depth first search).
In depth-first search the idea is to travel as deep as possible from neighbour to neighbour before backtracking. What determines how deep is possible is that you must follow edges, and you don't visit any vertex twice.
boost already provides it: see here
Use quick sort.
The nodes are sorted at lowermost level in multiple arrays & these arrays of sorted elements are merged i the end.
E.g.
Function quick_sort(node n)
1. Go to left mode, if is not null, call quick_sort on it.
2. Go to right elements, if is not null, call quick_sort on it.
3. Merge results of left node sort & right node sort & current node.
4. Return merged array.
I'm not getting the question. Aren't binary trees already sorted? If you'd like to print out the items in order (or access them in order), this code would work
/**
* Show the contents of the BST in order
*/
public void show () {
show(root);
System.out.println();
}
private static void show(TreeNode node) {
if (node == null) return;
show(node.lchild);
System.out.print(node.datum + " ");
show(node.rchild);
}
I believe this would be o(n) complexity. To return a list instead of printing, just create one and replace each show statement by adding the child to the list

Resources