Linked List in Binary Tree - algorithm

I'm trying to solve : https://leetcode.com/contest/weekly-contest-178/problems/linked-list-in-binary-tree/
I have the following solution :
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
boolean ans;
ListNode originalHead;
public boolean isSubPath(ListNode head, TreeNode root) {
this.ans = false;
originalHead = head;
traverse(head, root);
return ans;
}
public void traverse(ListNode head, TreeNode root) {
if(head == null) {
ans = true;
return;
}
if(root == null) return;
if(!ans && root.val == head.val) traverse(head.next, root.right);
if(!ans && root.val == head.val) traverse(head.next, root.left);
if(!ans) traverse(originalHead, root.right);
if(!ans) traverse(originalHead, root.left);
}
}
I'm wondering if this solution has a time complexity of O(n^2) or not. I ask this since I'm encountering a Time Limit Exceeded error for one of the test cases in the test suite.
I do see other O(n^2) solutions passing though.
Appreciate any help.
Thank you!

If n is the number of vertices in the tree, then your algorithm's worst-case time complexity is in Θ(2n) rather than O(n2).
This worst case occurs when every non-leaf node of the tree has just one child, the linked list is longer than the tree is deep, and all of the nodes in the tree and the linked list all have the same value. When that happens, you end up making all of your recursive calls — your if-conditions are always met — so each time you call traverse on a node, you call traverse twice on its child node. So you call traverse once on the root node, twice on its child, four times on its grandchild, eight times on its great-grandchild, etc., which is Θ(2n) if there are n nodes.

Related

Balanced tree with constant-time successor and predecessor given node pointers?

I was asked this question, which I personally find hard:
Create a data structure that can:
Insert elements,
Remove elements,
Search Elements,
In time O(log n)
In addition,
It should have the following two functions which work in time O(1):
next(x):
given a pointer to the node of value x, return a pointer to the node with the smallest bigger value than x.
previous(x)
given a pointer to the node of value x, return a pointer to the node with the biggest smallest value than x.
If each node contains a pointer to its successor and a pointer to its predecessor, or equivalently - if you maintain both a doublely linked list and a tree, where each node in the tree points to its equivalent node in the list and vice versa - you'll get want you want. Updating the list on insert/delete is O(1) (after locating the closest node in the tree). Searching is performed on the tree. Succesor / predecessor are performed on the list.
#RogerLindsjö's idea from the comments is a good one. Essentially, keep a regular, balanced BST, then thread a doubly-linked list through the nodes keeping them in sorted order. That way, given a pointer to a node in the tree, you can find the largest value smaller than it or the smallest value greater than it simply by following the next or previous pointers in each node.
You can maintain this list through insertions and deletions without changing the overall runtime of an insert or delete. For example, here's how you might do an insertion of an element x:
Do a standard BST successor query to find the smallest value larger than x in the tree, and a standard BST predecessor query to find the largest value smaller than x in the tree. Each search takes time O(log n) to complete.
Do a regular BST insertion to insert x. Then, set its next and previous pointers to the two elements you found in the previous step, and update those nodes to point to your new node x. This also takes time O(log n).
The total time for the insertion is then O(log n), matching what a balanced tree can provide.
I'll leave it to you to figure out deletion, which can similarly maintain the linked list pointers without changing the overall cost of the operation.
Like most self-balancing trees, a B+ tree provides Insert, Remove, and Search operations with O(log n) time complexity.
In a B+ tree, a leaf node hosts multiple keys in an array, so the concept of "pointer to node with value x" does not really exist, but we could define it as the tuple (pointer, index), where the pointer is to the node, and index is the slot in which x is stored.
In a B+ tree the nodes at the bottom level contain all the keys, and these nodes are often linked, usually only in forward direction (i.e. to the right), but it is quite possible to also maintain a link in the opposite direction, without increasing the time complexity of the above operations.
With those two remarks in mind, prev-next operations can clearly be executed in O(1) time.
If your elements are integers you can use y-fast trie that supports all mentioned operations in O(log log m). Also, almost any search tree will allow doing these operations in O(log n) time by just going first up and then down (it will require a lot of concentration to not mess up with the order, though)
You can use two pointers in the node of the balanced tree, namely pred - predecessor and succ - successor. While inserting a node into the tree or deleting a node from the tree you just have to do some pointer manipulations, equivalent to those in doubly linked list.
The time complexity will be O(1) in each case.
I have provided my implementation for the insertion and deletion in case of AVL Tree below. The complete implementation is available here.
Structure of node
template<typename T>
struct node {
T key;
int freq;
node<T> *left;
node<T> *right;
node<T> *pred;
node<T> *succ;
int height;
node(T key): key(key), freq(1),
left(nullptr),
right(nullptr),
height(1),
pred(nullptr),
succ(nullptr) {}
};
insert function
node<T> *insert(node<T> *root, T key) {
if(root == nullptr)
return new node<T>(key);
if(!comp(key, root->key) && !comp(root->key, key)) {
++root->freq;
} else if(comp(key, root->key)) {
if(root->left == nullptr) {
node<T> *new_node = new node<T>(key);
/* set the pred and succ ptrs*/
new_node->succ = root;
new_node->pred = root->pred;
if(root->pred != nullptr)
root->pred->succ = new_node;
root->pred = new_node;
root->left = new_node;
} else {
root->left = insert(root->left, key);
}
} else {
if(root->right == nullptr) {
node<T> *new_node = new node<T>(key);
/* set the pred and succ ptrs*/
new_node->pred = root;
new_node->succ = root->succ;
if(root->succ != nullptr)
root->succ->pred = new_node;
root->succ = new_node;
root->right = new_node;
} else {
root->right = insert(root->right, key);
}
}
root->height = max(height(root->left), height(root->right)) + 1;
int bf = balance_factor(root);
node<T> *left = root->left;
node<T> *right = root->right;
if(bf > 1 && left != nullptr && comp(key, left->key)) {
/*
node was inserted at left subtree of left child
fix - right rotate root
*/
root = rotate_right(root);
} else if(bf > 1 && left != nullptr && comp(left->key, key)) {
/*
node was inserted at right subtree of left child
fix - left rotate left child
- right rotate root
*/
root->left = rotate_left(root->left);
root = rotate_right(root);
} else if(bf < -1 && right != nullptr && comp(right->key, key)) {
/*
node was inserted at right subtree of right child
fix - left rotate root
*/
root = rotate_left(root);
} else if(bf < -1 && right != nullptr && comp(key, right->key)) {
/*
node was inserted at left subtree of right child
fix - right rotate right child
- left roatate root
*/
root->right = rotate_right(root->right);
root = rotate_left(root);
}
return root;
}
erase function
node<T> *erase(node<T> *root, T key) {
if(root == nullptr)
return nullptr;
if(comp(key, root->key)) {
root->left = erase(root->left, key);
} else if(comp(root->key, key)) {
root->right = erase(root->right, key);
} else {
if(root->left == nullptr || root->right == nullptr) {
/* update pred and succ ptrs */
if(root->succ != nullptr)
root->succ->pred = root->pred;
if(root->pred != nullptr)
root->pred->succ = root->succ;
if(root->right == nullptr) {
node<T> *temp = root->left;
delete root;
root = temp;
} else {
node<T> *temp = root->right;
delete root;
root = temp;
}
} else {
// node<T> *succ = minVal(root->right);
root->key = root->succ->key;
root->freq = root->succ->freq;
root->right = erase(root->right, root->succ->key);
}
}
if(root != nullptr) {
root->height = max(height(root->left), height(root->right)) + 1;
int bf_root = balance_factor(root);
if(bf_root > 1) {
/*
case R
*/
int bf_left = balance_factor(root->left);
if(bf_left >= 0) {
/*
case R0 and R1
*/
root = rotate_right(root);
} else {
/*
case R -1
*/
root->left = rotate_left(root->left);
root = rotate_right(root);
}
} else if(bf_root < -1) {
/*
Case L
*/
int bf_right = balance_factor(root->right);
if(bf_right <= 0) {
/*
case L0 and L -1
*/
root = rotate_left(root);
} else {
/*
case L1
*/
root->right = rotate_right(root->right);
root = rotate_left(root);
}
}
}
return root;
}

How to calculate a height of a tree

I am trying to learn DSA and got stuck on one problem.
How to calculate height of a tree. I mean normal tree, not any specific implementation of tree like BT or BST.
I have tried google but seems everyone is talking about Binary tree and nothing is available for normal tree.
Can anyone help me to redirect to some page or articles to calculate height of a tree.
Lets say a typical node in your tree is represented as Java class.
class Node{
Entry entry;
ArrayList<Node> children;
Node(Entry entry, ArrayList<Node> children){
this.entry = entry;
this.children = children;
}
ArrayList<Node> getChildren(){
return children;
}
}
Then a simple Height Function can be -
int getHeight(Node node){
if(node == null){
return 0;
}else if(node.getChildren() == null){
return 1;
} else{
int childrenMaxHeight = 0;
for(Node n : node.getChildren()){
childrenMaxHeight = Math.max(childrenMaxHeight, getHeight(n));
}
return 1 + childrenMaxHeight;
}
}
Then you just need to call this function passing the root of tree as argument. Since it traverse all the node exactly once, the run time is O(n).
1. If height of leaf node is considered as 0 / Or height is measured depending on number of edges in longest path from root to leaf :
int maxHeight(treeNode<int>* root){
if(root == NULL)
return -1; // -1 beacuse since a leaf node is 0 then NULL node should be -1
int h=0;
for(int i=0;i<root->childNodes.size();i++){
temp+=maxHeight(root->childNodes[i]);
if(temp>h){
h=temp;
}
}
return h+1;
}
2. If height of root node is considered 1:
int maxHeight(treeNode<int>* root){
if(root == NULL)
return 0;
int h=0;
for(int i=0;i<root->childNodes.size();i++){
temp+=maxHeight(root->childNodes[i]);
if(temp>h){
h=temp;
}
}
return h+1;
Above Code is based upon following class :
template <typename T>
class treeNode{
public:
T data;
vector<treeNode<T>*> childNodes; // vector for storing pointer to child treenode
creating Tree node
treeNode(T data){
this->data = data;
}
};
In case of 'normal tree' you can recursively calculate the height of tree in similar fashion to a binary tree but here you will have to consider all children at a node instead of just two.
To find a tree height a BFS iteration will work fine.
Edited form Wikipedia:
Breadth-First-Search(Graph, root):
create empty set S
create empty queues Q1, Q2
root.parent = NIL
height = -1
Q1.enqueue(root)
while Q1 is not empty:
height = height + 1
switch Q1 and Q2
while Q2 is not empty:
for each node n that is adjacent to current:
if n is not in S:
add n to S
n.parent = current
Q1.enqueue(n)
You can see that adding another queue allows me to know what level of the tree.
It iterates for each level, and for each mode in that level.
This is a discursion way to do it (opposite of recursive). So you don't have to worry about that too.
Run time is O(|V|+ |E|).

How binary search tree is created?

Suppose i am having an array say
1 5 4 6 8 9 10 22 17 7 9 3
I want to create a binary search tree from this array. I need algorithm to understand that.
I have read rest other things related to BST like inorder traversal preorder postorder, tree walk, insertion deletion etc
Book has not provided how to create BST. Need help here
if you do not care about the tree being balanced it is simple:
put the first element of the tree as the head.
iterate over the array. if an element is bigger than the node take a left(repeat the step for the left child) otherwise take a right(repeat the step for the right child).
if the left/right child is a null insert your new value there.
guaranteed to produce a binary search tree - just not a balanced one.
Firstly, you should choose a root node for your BST. Once you have chosen a root node, it is already easy to construct a BST taking into consideration the fact that: left children are less than the parent node and all right children are greater than the parent node.
private Node root;
public void insert(int val) {
if (root == null) {
root = new Node(val);
} else {
insertHelper(root, val);
}
}
private void insertHelper(Node node, int val) {
if (val < node.val) {
if (node.left == null) {
node.left = new Node(val);
} else {
insertHelper(node.left, val);
}
} else if (node.val < val) {
if (node.right == null) {
node.right = new Node(val);
} else {
insertHelper(node.right, val);
}
}
}
If the given array is sorted, you can do the following:
Take the middle element of the array and make it the root of the tree
Take the left sub-array and make it the left sub-tree of the root recursively
Take the right sub-array and make it the right sub-tree of the root recursively
Otherwise you can always sort the array before applying the procedure
struct node* construct(int arr[], int start, int end)
{
if(start>end)
return;
else if (start==end)
{
/*assuming we have a function newNode(int) which creates a new BST Node*/
node* Node = newNode(arr[start]);
return Node;
}
int mid = (start+end)/2;
node* root = newNode(arr[mid]);
root->left = construct(arr,start,mid-1);
root->right = construct(arr,mid+1,end);
return root;
}

Merging 2 Binary Search Trees

How do you merge 2 Binary Search Trees in such a way that the resultant tree contains all the elements of both the trees and also maintains the BST property.
I saw the solution provided in
How to merge two BST's efficiently?
However that solution involves converting into a Double Linked List. I was wondering if there is a more elegant way of doing this which could be done in place without the conversion. I came up with the following pseudocode. Does it work for all cases? Also I am having trouble with the 3rd case.
node* merge(node* head1, node* head2) {
if (!head1)
return head2;
if (!head2)
return head1;
// Case 1.
if (head1->info > head2->info) {
node* temp = head2->right;
head2->right = NULL;
head1->left = merge(head1->left, head2);
head1 = merge(head1, temp);
return head1;
} else if (head1->info < head2->info) { // Case 2
// Similar to case 1.
} else { // Case 3
// ...
}
}
The two binary search trees (BST) cannot be merged directly during a recursive traversal.
Suppose we should merge Tree 1 and Tree 2 shown in the figure.
The recursion should reduce the merging to a simpler situation. We cannot reduce
the merging only to the respective left subtrees L1 and L2, because L2 can contain
numbers larger than 10, so we would need to include the right
subtree R1 into the process. But then we include numbers greater
than 10 and possibly greater than 20, so we would need to include
the right subtree R2 as well. A similar reasoning shows that
we cannot simplify the merging by including subtrees from Tree 1 and from Tree 2
at the same time.
The only possibility for reduction is to simplify only inside the respective trees.
So, we can transform
the trees to their right spines with sorted nodes:
Now, we can merge the two spines easily into one spine. This
spine is in fact a BST, so we could stop here. However, this BST
is completely unbalanced, so we transform it to a balanced BST.
The complexity is:
Spine 1: time = O(n1), space = O(1)
Spine 2: time = O(n2), space = O(1)
Merge: time = O(n1+n2), space = O(1)
Balance: time = O(n1+n2), space = O(1)
Total: time = O(n1+n2), space = O(1)
The complete running code is on http://ideone.com/RGBFQ. Here are the essential parts. The top level code is a follows:
Node* merge(Node* n1, Node* n2) {
Node *prev, *head1, *head2;
prev = head1 = 0; spine(n1, prev, head1);
prev = head2 = 0; spine(n2, prev, head2);
return balance(mergeSpines(head1, head2));
}
The auxiliary functions are for the tranformation to spines:
void spine(Node *p, Node *& prev, Node *& head) {
if (!p) return;
spine(p->left, prev, head);
if (prev) prev->right = p;
else head = p;
prev = p;
p->left = 0;
spine(p->right, prev, head);
}
Merging of the spines:
void advance(Node*& last, Node*& n) {
last->right = n;
last = n;
n = n->right;
}
Node* mergeSpines(Node* n1, Node* n2) {
Node head;
Node* last = &head;
while (n1 || n2) {
if (!n1) advance(last, n2);
else if (!n2) advance(last, n1);
else if (n1->info < n2->info) advance(last, n1);
else if (n1->info > n2->info) advance(last, n2);
else {
advance(last, n1);
printf("Duplicate key skipped %d \n", n2->info);
n2 = n2->right;
}
}
return head.right;
}
Balancing:
Node* balance(Node *& list, int start, int end) {
if (start > end) return NULL;
int mid = start + (end - start) / 2;
Node *leftChild = balance(list, start, mid-1);
Node *parent = list;
parent->left = leftChild;
list = list->right;
parent->right = balance(list, mid+1, end);
return parent;
}
Node* balance(Node *head) {
int size = 0;
for (Node* n = head; n; n = n->right) ++size;
return balance(head, 0, size-1);
}
Assuming we have two trees A and B we insert root of tree A into tree B and using rotations move inserted root to become new root of tree B. Next we recursively merge left and right sub-trees of trees A and B. This algorithm takes into account both trees structure but insertion still depends on how balanced target tree is. You can use this idea to merge the two trees in O(n+m) time and O(1) space.
The following implementation is due to Dzmitry Huba:
// Converts tree to sorted singly linked list and appends it
// to the head of the existing list and returns new head.
// Left pointers are used as next pointer to form singly
// linked list thus basically forming degenerate tree of
// single left oriented branch. Head of the list points
// to the node with greatest element.
static TreeNode<T> ToSortedList<T>(TreeNode<T> tree, TreeNode<T> head)
{
if (tree == null)
// Nothing to convert and append
return head;
// Do conversion using in order traversal
// Convert first left sub-tree and append it to
// existing list
head = ToSortedList(tree.Left, head);
// Append root to the list and use it as new head
tree.Left = head;
// Convert right sub-tree and append it to list
// already containing left sub-tree and root
return ToSortedList(tree.Right, tree);
}
// Merges two sorted singly linked lists into one and
// calculates the size of merged list. Merged list uses
// right pointers to form singly linked list thus forming
// degenerate tree of single right oriented branch.
// Head points to the node with smallest element.
static TreeNode<T> MergeAsSortedLists<T>(TreeNode<T> left, TreeNode<T> right, IComparer<T> comparer, out int size)
{
TreeNode<T> head = null;
size = 0;
// See merge phase of merge sort for linked lists
// with the only difference in that this implementations
// reverts the list during merge
while (left != null || right != null)
{
TreeNode<T> next;
if (left == null)
next = DetachAndAdvance(ref right);
else if (right == null)
next = DetachAndAdvance(ref left);
else
next = comparer.Compare(left.Value, right.Value) > 0
? DetachAndAdvance(ref left)
: DetachAndAdvance(ref right);
next.Right = head;
head = next;
size++;
}
return head;
}
static TreeNode<T> DetachAndAdvance<T>(ref TreeNode<T> node)
{
var tmp = node;
node = node.Left;
tmp.Left = null;
return tmp;
}
// Converts singly linked list into binary search tree
// advancing list head to next unused list node and
// returning created tree root
static TreeNode<T> ToBinarySearchTree<T>(ref TreeNode<T> head, int size)
{
if (size == 0)
// Zero sized list converts to null
return null;
TreeNode<T> root;
if (size == 1)
{
// Unit sized list converts to a node with
// left and right pointers set to null
root = head;
// Advance head to next node in list
head = head.Right;
// Left pointers were so only right needs to
// be nullified
root.Right = null;
return root;
}
var leftSize = size / 2;
var rightSize = size - leftSize - 1;
// Create left substree out of half of list nodes
var leftRoot = ToBinarySearchTree(ref head, leftSize);
// List head now points to the root of the subtree
// being created
root = head;
// Advance list head and the rest of the list will
// be used to create right subtree
head = head.Right;
// Link left subtree to the root
root.Left = leftRoot;
// Create right subtree and link it to the root
root.Right = ToBinarySearchTree(ref head, rightSize);
return root;
}
public static TreeNode<T> Merge<T>(TreeNode<T> left, TreeNode<T> right, IComparer<T> comparer)
{
Contract.Requires(comparer != null);
if (left == null || right == null)
return left ?? right;
// Convert both trees to sorted lists using original tree nodes
var leftList = ToSortedList(left, null);
var rightList = ToSortedList(right, null);
int size;
// Merge sorted lists and calculate merged list size
var list = MergeAsSortedLists(leftList, rightList, comparer, out size);
// Convert sorted list into optimal binary search tree
return ToBinarySearchTree(ref list, size);
}
The best way we could merge the trees in place is something like:
For each node n in first BST {
Go down the 2nd tree and find the appropriate place to insert n
Insert n there
}
Each iteration in the for loop is O(log n) since we are dealing with trees, and the for loop will be iterated n times, so in total we have O(n log n).
A BST is a ordered or sorted binary tree. My algorithm would be to simple :
traverse through both trees
compare the values
insert the smaller of the two into a new BST.
The python code for traversing is as follows:
def traverse_binary_tree(node, callback):
if node is None:
return
traverse_binary_tree(node.leftChild, callback)
callback(node.value)
traverse_binary_tree(node.rightChild, callback)
The cost for traversing through the BST and building a new merged BST would remain O(n)
This blog post provides a solution to the problem with O(logn) space complexity. (Pay attention that the given approach does not modify input trees.)
This can be done in 3 steps:
covert the BSTs to sorted linked list (this can be done in place with O(m+n) time)
Merge this two sorted linked lists to a single list (this can be done in place with O(m+n) time)
Convert sorted linked list to balanced BST (this can be done in place with O(m+n) time)
Here is what I would do.
This solution is O(n1+n2) time complexity.
STEPS:
Perform the inorder traversal of both the trees to get sorted arrays --> linear time
Merge the two arrays --> again linear time
Convert the merged array into a Balanced binary search tree --> again linear time
This would require O(n1+n2) time and space.
Links you may find useful while implementing:
How to merge 2 sorted arrays
Inorder traversal
Sorted array to a balanced BST
The following algorithm is from Algorithms in C++.
The idea is almost the same as in the algorithm posted by PengOne. This algorithm does in place merging, time complexity is O(n+m).
link join(link a, link b) {
if (b == 0) return a;
if (a == 0) return b;
insert(b, a->item);
b->left = join(a->left, b->left);
b->right = join(a->right, b->right);
delete a;
return b;
}
insert just inserts an item in the right place in the tree.
void insert(link &h, Item x) {
if (h == 0) {
h = new node(x);
return;
}
if (x.key() < h->item.key()) {
insert(h->left, x);
rotateRight(h);
}
else {
insert(h->right, x);
rotateLeft(h);
}
}
rotateRight and rotateLeft keep tree in the right order.
void rotateRight(link &h) {
link x = h->left;
h->left = x->right;
x->right = h;
h = x;
}
void rotateLeft(link &h) {
link x = h->right;
h->right = x->left;
x->left = h;
h = x;
}
Here link is node *.
Assuming the question is just to print sorted from both BSTs. Then the easier way is,
Store inorder traversal of 2 BSTs in 2 seperate arrays.
Now the problem reduces to merging\printing elements from 2 sorted arrays, which we got from step one. This merging can be done in o(m) when m>n or o(n) when m
Complexity: o(m+n)
Aux space: o(m+n) for the 2 arrays
MergeTwoBST_to_BalancedBST.java
public class MergeTwoBST_to_BalancedBST {
// arr1 and arr2 are the input arrays to be converted into a binary search
// structure and then merged and then balanced.
int[] arr1 = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 };
int[] arr2 = new int[] { 11, 12, 13, 14, 15, 16, 17, 18 };
BSTNode root1;
BSTNode root2;
// vector object to hold the nodes from the merged unbalanced binary search
// tree.
Vector<BSTNode> vNodes = new Vector<BSTNode>();
/**
* Constructor to initialize the Binary Search Tree root nodes to start
* processing. This constructor creates two trees from two given sorted
* array inputs. root1 tree from arr1 and root2 tree from arr2.
*
* Once we are done with creating the tree, we are traversing the tree in
* inorder format, to verify whether nodes are inserted properly or not. An
* inorder traversal should give us the nodes in a sorted order.
*/
public MergeTwoBST_to_BalancedBST() {
// passing 0 as the startIndex and arr1.length-1 as the endIndex.
root1 = getBSTFromSortedArray(arr1, 0, arr1.length - 1);
System.out.println("\nPrinting the first binary search tree");
inorder(root1); // traverse the tree in inorder format to verify whether
// nodes are inserted correctly or not.
// passing 0 as the startIndex and arr2.length-1 as the endIndex.
root2 = getBSTFromSortedArray(arr2, 0, arr2.length - 1);
System.out.println("\nPrinting the second binary search tree");
inorder(root2); // same here - checking whether the nodes are inserted
// properly or not.
}
/**
* Method to traverse the tree in inorder format. Where it traverses the
* left child first, then root and then right child.
*
* #param node
*/
public void inorder(BSTNode node) {
if (null != node) {
inorder(node.getLeft());
System.out.print(node.getData() + " ");
inorder(node.getRight());
}
}
/**
* Method to traverse the tree in preorder format. Where it traverses the
* root node first, then left child and then right child.
*
* #param node
*/
public void preorder(BSTNode node) {
if (null != node) {
System.out.print(node.getData() + " ");
preorder(node.getLeft());
preorder(node.getRight());
}
}
/**
* Creating a new Binary Search Tree object from a sorted array and
* returning the root of the newly created node for further processing.
*
* #param arr
* #param startIndex
* #param endIndex
* #return
*/
public BSTNode getBSTFromSortedArray(int[] arr, int startIndex, int endIndex) {
if (startIndex > endIndex) {
return null;
}
int middleIndex = startIndex + (endIndex - startIndex) / 2;
BSTNode node = new BSTNode(arr[middleIndex]);
node.setLeft(getBSTFromSortedArray(arr, startIndex, middleIndex - 1));
node.setRight(getBSTFromSortedArray(arr, middleIndex + 1, endIndex));
return node;
}
/**
* This method involves two operation. First - it adds the nodes from root1
* tree to root2 tree, and hence we get a merged root2 tree.Second - it
* balances the merged root2 tree with the help of a vector object which can
* contain objects only of BSTNode type.
*/
public void mergeTwoBinarySearchTree() {
// First operation - merging the trees. root1 with root2 merging should
// give us a new root2 tree.
addUtil(root1);
System.out.println("\nAfter the root1 tree nodes are added to root2");
System.out.println("Inorder Traversal of root2 nodes");
inorder(root2); // inorder traversal of the root2 tree should display
// the nodes in a sorted order.
System.out.println("\nPreorder traversal of root2 nodes");
preorder(root2);
// Second operation - this will take care of balancing the merged binary
// search trees.
balancedTheMergedBST();
}
/**
* Here we are doing two operations. First operation involves, adding nodes
* from root2 tree to the vector object. Second operation involves, creating
* the Balanced binary search tree from the vector objects.
*/
public void balancedTheMergedBST() {
// First operation : adding nodes to the vector object
addNodesToVector(root2, vNodes);
int vSize = vNodes.size();
// Second operation : getting a balanced binary search tree
BSTNode node = getBalancedBSTFromVector(vNodes, 0, vSize - 1);
System.out
.println("\n********************************************************");
System.out.println("After balancing the merged trees");
System.out.println("\nInorder Traversal of nodes");
inorder(node); // traversing the tree in inoder process should give us
// the output in sorted order ascending
System.out.println("\nPreorder traversal of root2 nodes");
preorder(node);
}
/**
* This method will provide us a Balanced Binary Search Tree. Elements of
* the root2 tree has been added to the vector object. It is parsed
* recursively to create a balanced tree.
*
* #param vNodes
* #param startIndex
* #param endIndex
* #return
*/
public BSTNode getBalancedBSTFromVector(Vector<BSTNode> vNodes,
int startIndex, int endIndex) {
if (startIndex > endIndex) {
return null;
}
int middleIndex = startIndex + (endIndex - startIndex) / 2;
BSTNode node = vNodes.get(middleIndex);
node.setLeft(getBalancedBSTFromVector(vNodes, startIndex,
middleIndex - 1));
node.setRight(getBalancedBSTFromVector(vNodes, middleIndex + 1,
endIndex));
return node;
}
/**
* This method traverse the tree in inorder process and adds each node from
* root2 to the vector object vNodes object only accepts objects of BSTNode
* type.
*
* #param node
* #param vNodes
*/
public void addNodesToVector(BSTNode node, Vector<BSTNode> vNodes) {
if (null != node) {
addNodesToVector(node.getLeft(), vNodes);
// here we are adding the node in the vector object.
vNodes.add(node);
addNodesToVector(node.getRight(), vNodes);
}
}
/**
* This method traverse the root1 tree in inorder process and add the nodes
* in the root2 tree based on their value
*
* #param node
*/
public void addUtil(BSTNode node) {
if (null != node) {
addUtil(node.getLeft());
mergeToSecondTree(root2, node.getData());
addUtil(node.getRight());
}
}
/**
* This method adds the nodes found from root1 tree as part it's inorder
* traversal and add it to the second tree.
*
* This method follows simple Binary Search Tree inserstion logic to insert
* a node considering the tree already exists.
*
* #param node
* #param data
* #return
*/
public BSTNode mergeToSecondTree(BSTNode node, int data) {
if (null == node) {
node = new BSTNode(data);
} else {
if (data < node.getData()) {
node.setLeft(mergeToSecondTree(node.getLeft(), data));
} else if (data > node.getData()) {
node.setRight(mergeToSecondTree(node.getRight(), data));
}
}
return node;
}
/**
*
* #param args
*/
public static void main(String[] args) {
MergeTwoBST_to_BalancedBST mergeTwoBST = new MergeTwoBST_to_BalancedBST();
mergeTwoBST.mergeTwoBinarySearchTree();
}
}
BSTNode.java:
public class BSTNode {
BSTNode left, right;
int data;
/* Default constructor */
public BSTNode() {
left = null;
right = null;
data = 0;
}
/* Constructor */
public BSTNode(int data) {
left = null;
right = null;
this.data = data;
}
public BSTNode getLeft() {
return left;
}
public void setLeft(BSTNode left) {
this.left = left;
}
public BSTNode getRight() {
return right;
}
public void setRight(BSTNode right) {
this.right = right;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}

Binary tree level order traversal

Three types of tree traversals are inorder, preorder, and post order.
A fourth, less often used, traversal is level-order traversal. In a
level-order traveresal, all nodes at depth "d" are processed before
any node at depth d + 1. Level-order traversal differs from the other
traversals in that it is not done recursively; a queue is used,
instead of the implied stack of recursion.
My questions on above text snippet are
Why level order traversals are not done recursively?
How queue is used in level order traversal? Request clarification with Pseudo code will be helpful.
Thanks!
Level order traversal is actually a BFS, which is not recursive by nature. It uses Queue instead of Stack to hold the next vertices that should be opened. The reason for it is in this traversal, you want to open the nodes in a FIFO order, instead of a LIFO order, obtained by recursion
as I mentioned, the level order is actually a BFS, and its [BFS] pseudo code [taken from wikipedia] is:
1 procedure BFS(Graph,source):
2 create a queue Q
3 enqueue source onto Q
4 mark source
5 while Q is not empty:
6 dequeue an item from Q into v
7 for each edge e incident on v in Graph:
8 let w be the other end of e
9 if w is not marked:
10 mark w
11 enqueue w onto Q
(*) in a tree, marking the vertices is not needed, since you cannot get to the same node in 2 different paths.
void levelorder(Node *n)
{ queue < Node * >q;
q.push(n);
while(!q.empty())
{
Node *node = q.front();
cout<<node->value;
q.pop();
if(node->left != NULL)
q.push(node->left);
if (node->right != NULL)
q.push(node->right);
}
}
Instead of a queue, I used a map to solve this. Take a look, if you are interested. As I do a postorder traversal, I maintain the depth at which each node is positioned and use this depth as the key in a map to collect values in the same level
class Solution {
public:
map<int, vector<int> > levelValues;
void recursivePrint(TreeNode *root, int depth){
if(root == NULL)
return;
if(levelValues.count(root->val) == 0)
levelValues.insert(make_pair(depth, vector<int>()));
levelValues[depth].push_back(root->val);
recursivePrint(root->left, depth+1);
recursivePrint(root->right, depth+1);
}
vector<vector<int> > levelOrder(TreeNode *root) {
recursivePrint(root, 1);
vector<vector<int> > result;
for(map<int,vector<int> >::iterator it = levelValues.begin(); it!= levelValues.end(); ++it){
result.push_back(it->second);
}
return result;
}
};
The entire solution can be found here - http://ideone.com/zFMGKU
The solution returns a vector of vectors with each inner vector containing the elements in the tree in the correct order.
you can try solving it here - https://oj.leetcode.com/problems/binary-tree-level-order-traversal/
And, as you can see, we can also do this recursively in the same time and space complexity as the queue solution!
My questions on above text snippet are
Why level order traversals are not done recursively?
How queue is used in level order traversal? Request clarification with Pseudo code will be helpful.
I think it'd actually be easier to start with the second question. Once you understand the answer to the second question, you'll be better prepared to understand the answer to the first.
How level order traversal works
I think the best way to understand how level order traversal works is to go through the execution step by step, so let's do that.
We have a tree.
We want to traverse it level by level.
So, the order that we'd visit the nodes would be A B C D E F G.
To do this, we use a queue. Remember, queues are first in, first out (FIFO). I like to imagine that the nodes are waiting in line to be processed by an attendant.
Let's start by putting the first node A into the queue.
Ok. Buckle up. The setup is over. We're about to start diving in.
The first step is to take A out of the queue so it can be processed. But wait! Before we do so, let's put A's children, B and C, into the queue also.
Note: A isn't actually in the queue anymore at this point. I grayed it out to try to communicate this. If I removed it completely from the diagram, it'd make it harder to visualize what's happening later on in the story.
Note: A is being processed by the attendant at the desk in the diagram. In real life, processing a node can mean a lot of things. Using it to compute a sum, send an SMS, log to the console, etc, etc. Going off the metaphor in my diagram, you can tell the attendant how you want them to process the node.
Now we move on to the node that is next in line. In this case, B.
We do the same thing that we did with A: 1) add the children to the line, and 2) process the node.
Hey, check it out! It looks like what we're doing here is going to get us that level order traversal that we were looking for! Let's prove this to ourselves by continuing the step through.
Once we finish with B, C is next in line. We place C's children at the back of the line, and then process C.
Now let's see what happens next. D is next in line. D doesn't have any children, so we don't place anything at the back of the line. We just process D.
And then it's the same thing for E, F, and G.
Why it's not done recursively
Imagine what would happen if we used a stack instead of a queue. Let's rewind to the point where we had just visited A.
Here's how it'd look if we were using a stack.
Now, instead of going "in order", this new attendant likes to serve the most recent clients first, not the ones who have been waiting the longest. So C is who is up next, not B.
Here's where the key point is. Where the stack starts to cause a different processing order than we had with the queue.
Like before, we add C's children and then process C. We're just adding them to a stack instead of a queue this time.
Now, what's next? This new attendant likes to serve the most recent clients first (ie. we're using a stack), so G is up next.
I'll stop the execution here. The point is that something as simple as replacing the queue with a stack actually gives us a totally different execution order. I'd encourage you to finish the step through though.
You might be thinking: "Ok... but the question asked about recursion. What does this have to do with recursion?" Well, when you use recursion, something sneaky is going on. You never did anything with a stack data structure like s = new Stack(). However, the runtime uses the call stack. This ends up being conceptually similar to what I did above, and thus doesn't give us that A B C D E F G ordering we were looking for from level order traversal.
https://github.com/arun2pratap/data-structure/blob/master/src/main/java/com/ds/tree/binarytree/BinaryTree.java
for complete can look out for the above link.
public void levelOrderTreeTraversal(List<Node<T>> nodes){
if(nodes == null || nodes.isEmpty()){
return;
}
List<Node<T>> levelNodes = new ArrayList<>();
nodes.stream().forEach(node -> {
if(node != null) {
System.out.print(" " + node.value);
levelNodes.add(node.left);
levelNodes.add(node.right);
}
});
System.out.println("");
levelOrderTreeTraversal(levelNodes);
}
Also can check out
http://www.geeksforgeeks.org/
here you will find Almost all Data Structure related answers.
Level order traversal implemented by queue
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
def levelOrder(root: TreeNode) -> List[List[int]]:
res = [] # store the node value
queue = [root]
while queue:
node = queue.pop()
# visit the node
res.append(node.val)
if node.left:
queue.insert(0, node.left)
if node.right:
queue.insert(0, node.right)
return res
Recursive implementation is also possible. However, it needs to know the max depth of the root in advance.
def levelOrder(root: TreeNode) -> List[int]:
res = []
max_depth = maxDepth(root)
for i in range(max_depth):
# level start from 0 to max_depth-1
visitLevel(root, i, action)
return res
def visitLevel(root:TreeNode, level:int, res: List):
if not root:
return
if level==0:
res.append(node.val)
else:
self.visitLevel(root.left, level-1, res)
self.visitLevel(root.right, level-1, res)
def maxDepth(root: TreeNode) -> int:
if not root:
return 0
if not root.left and not root.right:
return 1
return max([ maxDepth(root.left), maxDepth(root.right)]) + 1
For your point 1) we can use Java below code for level order traversal in recursive order, we have not used any library function for tree, all are user defined tree and tree specific functions -
class Node
{
int data;
Node left, right;
public Node(int item)
{
data = item;
left = right = null;
}
boolean isLeaf() { return left == null ? right == null : false; }
}
public class BinaryTree {
Node root;
Queue<Node> nodeQueue = new ConcurrentLinkedDeque<>();
public BinaryTree() {
root = null;
}
public static void main(String args[]) {
BinaryTree tree = new BinaryTree();
tree.root = new Node(1);
tree.root.left = new Node(2);
tree.root.right = new Node(3);
tree.root.left.left = new Node(4);
tree.root.left.right = new Node(5);
tree.root.right.left = new Node(6);
tree.root.right.right = new Node(7);
tree.root.right.left.left = new Node(8);
tree.root.right.left.right = new Node(9);
tree.printLevelOrder();
}
/*Level order traversal*/
void printLevelOrder() {
int h = height(root);
int i;
for (i = 1; i <= h; i++)
printGivenLevel(root, i);
System.out.println("\n");
}
void printGivenLevel(Node root, int level) {
if (root == null)
return;
if (level == 1)
System.out.print(root.data + " ");
else if (level > 1) {
printGivenLevel(root.left, level - 1);
printGivenLevel(root.right, level - 1);
}
}
/*Height of Binary tree*/
int height(Node root) {
if (root == null)
return 0;
else {
int lHeight = height(root.left);
int rHeight = height(root.right);
if (lHeight > rHeight)
return (lHeight + 1);
else return (rHeight + 1);
}
}
}
For your point 2) If you want to use non recursive function then you can use queue as below function-
public void levelOrder_traversal_nrec(Node node){
System.out.println("Level order traversal !!! ");
if(node == null){
System.out.println("Tree is empty");
return;
}
nodeQueue.add(node);
while (!nodeQueue.isEmpty()){
node = nodeQueue.remove();
System.out.printf("%s ",node.data);
if(node.left !=null)
nodeQueue.add(node.left);
if (node.right !=null)
nodeQueue.add(node.right);
}
System.out.println("\n");
}
Recursive Solution in C++
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> levels;
void helper(TreeNode* node,int level)
{
if(levels.size() == level) levels.push_back({});
levels[level].push_back(node->val);
if(node->left)
helper(node->left,level+1);
if(node->right)
helper(node->right,level+1);
}
vector<vector<int>> levelOrder(TreeNode* root) {
if(!root) return levels;
helper(root,0);
return levels;
}
};
We can use queue to solve this problem in less time complexity. Here is the solution of level order traversal suing Java.
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> levelOrderTraversal = new ArrayList<List<Integer>>();
List<Integer> currentLevel = new ArrayList<Integer>();
Queue<TreeNode> queue = new LinkedList<TreeNode>();
if(root != null)
{
queue.add(root);
queue.add(null);
}
while(!queue.isEmpty())
{
TreeNode queueRoot = queue.poll();
if(queueRoot != null)
{
currentLevel.add(queueRoot.val);
if(queueRoot.left != null)
{
queue.add(queueRoot.left);
}
if(queueRoot.right != null)
{
queue.add(queueRoot.right);
}
}
else
{
levelOrderTraversal.add(currentLevel);
if(!queue.isEmpty())
{
currentLevel = new ArrayList<Integer>();
queue.add(null);
}
}
}
return levelOrderTraversal;
}
}

Resources