Reordering a binary search tree within the tree itself - binary-tree

If I am given a binary tree that is unordered, what would be the best method of ordering it without just creating a new tree? When I say ordered, I mean such that all nodes in a left subtree is less than the root node and all nodes in a right subtree is greater than the root node.
I appreciate that the most optimal way to make an undordered binary tree into a binary seach tree is to extract all the nodes then insert them into a new tree, but is there another approach involving switching the placement of nodes in the original tree that could be done algorithmically?

The method of creating a new tree is certainly the way to go, but just as an excercise, it is possible to sort a binary tree in-place.
You could for instance implement bubble sort, such that all nodes remain in place, but their values are swapped in the process.
For this to work you need to implement an inorder traversal. Then keep repeating a full inorder traversal, where you compare the values of two successively visited nodes, and swap their values if they are not in the right order. When an inorder traversal does not result in at least one swap, the tree is sorted and the process can stop.
Here is an implementation in JavaScript:
It first generates a tree with 10 nodes having randomly unsigned integers below 100. The shape of the tree is random too (based on a random "path" that is provided with each insertion)
Then it sorts the tree as described above. As JavaScript has support for generators and iterators, I have used that syntax, but it could also be done with a callback system.
It displays the tree in a very rudimentary way (90° rotated, i.e. with the root at the left side), as it is before and after the sort operation.
class Node {
constructor(value) {
this.value = value;
this.left = this.right = null;
}
}
class Tree {
constructor() {
this.root = null;
}
// Method to add a value as a new leaf node, using the
// binary bits in the given path to determine
// the leaf's location:
addAtPath(value, path) {
function recur(node, path) {
if (!node) return new Node(value);
if (path % 2) {
node.right = recur(node.right, path >> 1);
} else {
node.left = recur(node.left, path >> 1);
}
return node;
}
this.root = recur(this.root, path);
}
*inorder() {
function* recur(node) {
if (!node) return;
yield* recur(node.left);
yield node;
yield* recur(node.right);
}
yield* recur(this.root);
}
toString() {
function recur(node, indent) {
if (!node) return "";
return recur(node.right, indent + " ")
+ indent + node.value + "\n"
+ recur(node.left, indent + " ");
}
return recur(this.root, "");
}
bubbleSort() {
let dirty = true;
while (dirty) {
dirty = false;
let iterator = this.inorder();
// Get first node from inorder traversal
let prevNode = iterator.next().value;
for (let currNode of iterator) { // Get all other nodes
if (prevNode.value > currNode.value) {
// Swap
const temp = prevNode.value;
prevNode.value = currNode.value;
currNode.value = temp;
dirty = true;
}
prevNode = currNode;
}
}
}
}
// Helper
const randInt = max => Math.floor(Math.random() * max);
// Demo:
const tree = new Tree();
for (let i = 0; i < 10; i++) {
tree.addAtPath(randInt(100), randInt(0x80000000));
}
console.log("Tree before sorting (root is at left, leaves at the right):");
console.log(tree.toString());
tree.bubbleSort();
console.log("Tree after sorting:");
console.log(tree.toString());
The time complexity is O(n²) -- typical for bubble sort.
This sorting does not change the shape of the tree -- all nodes stay where they are. Only the values are moved around.

Related

Is it possible to implement binary heap without using additional data structure (e.g. array, linked list)

Can I implement a binary heap by only using a TreeNode inferface (has children, or left/right, or/and parent.. something like this)?
I want to not rely on using array or linked list.
If I don't use array or linked list, I have a trouble inserting the next element in the correct place & keep it a complete binary tree (all non-leaf nodes are full). Also have trouble taking out the root and re-heapifying.
One key observation is this:
The path from the root to the last leaf in a complete binary tree is represented by the binary representation of the size of the tree (number of nodes in the tree).
For instance, this tree has 9 nodes.
1
/ \
4 2
/ \ / \
6 5 3 7
/ \
9 8
9 in binary is 1001. Skipping the most significant "1", this can be read from left-to-right as 0, 0, 1 or "left-left-right". That describes indeed the path from root to the leaf node with value 8!
The same principle holds for when you need to find the insertion point for a new node. Then first increase the size, so this becomes 10 in the example. The binary representation is 1010. Skipping the first digit, this represents "left-right-left". The last direction ("left") gives information about the edge that must be added. And indeed, "left-right" leads us to the node with value 5, and a new node has to be inserted as left-child of that node!
To restore the heap property after an insertion, keep track of the path towards the newly inserted leaf (for example, when coming back out of a recursive function), and wind that path back, each time verifying the heap property, and swapping values when necessary.
Similarly, for an extraction of the root value: first find the node to delete (see above), delete that node and assign the deleted value to the root node. Then sift down the heap to restore the heap property.
Here is an implementation in plain JavaScript -- it should be easy to port this to any other language:
class Node {
constructor(value) {
this.value = value;
this.left = this.right = null;
}
swapValueWith(other) { // We don't swap nodes, just their values
let temp = this.value;
this.value = other.value;
other.value = temp;
}
}
class HeapTree {
constructor() {
this.root = null;
this.size = 0;
}
insert(value) {
this.size++;
if (this.root == null) {
this.root = new Node(value);
} else { // Use the binary representation of the size to find insertion point
this.insertRecursive(this.root, 1 << (Math.floor(Math.log2(this.size)) - 1), value);
}
}
insertRecursive(node, bit, value) {
let side = this.size & bit;
let child;
if (side > 0) {
if (bit == 1) node.right = new Node(value);
child = node.right;
} else {
if (bit == 1) node.left = new Node(value);
child = node.left;
}
if (bit > 1) this.insertRecursive(child, bit>>1, value)
if (node.value > child.value) node.swapValueWith(child); // sift up
}
extract() {
if (this.root == null) return; // Nothing to extract
let value = this.root.value; // The value to return
if (this.size == 1) {
this.root = null;
} else {
// Use the binary representation of the size to find last leaf -- to be deleted
this.root.value = this.deleteRecursive(this.root, 1 << (Math.floor(Math.log2(this.size)) - 1));
// Sift down
let node = this.root;
while (true) {
let minNode = node;
if (node.left != null && node.left.value < minNode.value) minNode = node.left;
if (node.right != null && node.right.value < minNode.value) minNode = node.right;
if (minNode === node) break;
node.swapValueWith(minNode);
node = minNode;
}
}
this.size--;
return value;
}
deleteRecursive(node, bit) {
let side = this.size & bit;
let child;
if (side > 0) {
child = node.right;
if (bit == 1) node.right = null;
} else {
child = node.left;
if (bit == 1) node.left = null;
}
return bit == 1 ? child.value : this.deleteRecursive(child, bit>>1);
}
}
// Demo
let heap = new HeapTree();
for (let value of [4,2,5,8,7,9,0,3,1,6]){
heap.insert(value);
}
// Output the values in sorted order:
while (heap.root != null) {
console.log(heap.extract());
}

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|).

Implementing the Dutch National Flag Program with Linked Lists

I wanted to sort a linked list containing 0s, 1s or 2s. Now, this is clearly a variant of the Dutch National Flag Problem.
http://en.wikipedia.org/wiki/Dutch_national_flag_problem
The algorithm for the same as given in the link is:
"Have the top group grow down from the top of the array, the bottom group grow up from the bottom, and keep the middle group just above the bottom. The algorithm stores the locations just below the top group, just above the bottom, and just above the middle in three indexes. At each step, examine the element just above the middle. If it belongs to the top group, swap it with the element just below the top. If it belongs in the bottom, swap it with the element just above the bottom. If it is in the middle, leave it. Update the appropriate index. Complexity is Θ(n) moves and examinations."
And a C++ implementation given for the same is:
void threeWayPartition(int data[], int size, int low, int high) {
int p = -1;
int q = size;
for (int i = 0; i < q;) {
if (data[i] == low) {
swap(data[i], data[++p]);
++i;
} else if (data[i] >= high) {
swap(data[i], data[--q]);
} else {
++i;
}
}
}
My only question is how do we traverse back in a linked list like we are doing here in an array?
A standard singly-linked list doesn't allow you to move backwards given a linked list cell. However, you could use a doubly-linked list, where each cell stores a next and a previous pointer. That would let you navigate the list forwards and backwards.
However, for the particular problem you're trying to solve, I don't think this is necessary. One major difference between algorithms on arrays and on linked lists is that when working with linked lists, you can rearrange the cells in the list to reorder the elements in the list. Consequently, the algorithm you've detailed above - which works by changing the contents of the array - might not actually be the most elegant algorithm on linked lists.
If you are indeed working with linked lists, one possible way to solve this problem would be the following:
Create lists holding all values that are 0, 1, or 2.
Remove all cells from the linked list and distribute them into the list of elements that are equal to 0, 1, or 2.
Concatenate these three lists together.
This does no memory allocation and purely works by rearranging the linked list cells. It still runs in time Θ(n), which is another plus. Additionally, you can do this without ever having to walk backwards (i.e. this works on a singly-linked list).
I'll leave the complete implementation to you, but as an example, here's simple C++ code to distribute the linked list cells into the zero, one, and two lists:
struct Cell {
int value;
Cell* next;
}
/* Pointers to the heads of the three lists. */
Cell* lists[3] = { NULL, NULL, NULL };
/* Distribute the cells across the lists. */
while (list != NULL) {
/* Cache a pointer to the next cell in the list, since we will be
* rewiring this linked list.
*/
Cell* next = list->next;
/* Prepend this cell to the list it belongs to. */
list->next = lists[list->value];
lists[list->value] = list;
/* Advance to the next cell in the list. */
list = next;
}
Hope this helps!
As others have said, there is no way to "back up" in a linked list without reverse links. Though it's not exactly an answer to your question, the sort can be easily accomplished with three queues implementing a bucket sort with three buckets.
The advantage of queues (vice pushing on stacks) is that the sort is stable. That is, if there are data in the list nodes (other than the 0,1,2-valued keys), these will remain in the same order for each key.
This is only one of many cases where the canonical algorithm for arrays is not the best for lists.
There is a very slick, simple way to implement the queues: circularly linked lists where the first node, say p, is the tail of the queue and consequently p->next is is the head. With this, the code is concise.
#include <stdio.h>
#include <stdlib.h>
typedef struct node_s {
struct node_s *next;
int val;
int data;
} NODE;
// Add node to tail of queue q and return the new queue.
NODE *enqueue(NODE *q, NODE *node)
{
if (q) {
node->next = q->next;
q->next = node;
}
else node->next = node;
return node;
}
// Concatenate qa and qb and return the result.
NODE *cat(NODE *qa, NODE *qb)
{
NODE *head = qa->next;
qa->next = qb->next;
qb->next = head;
return qb;
}
// Sort a list where all values are 0, 1, or 2.
NODE *sort012(NODE *list)
{
NODE *next = NULL, *q[3] = { NULL, NULL, NULL};
for (NODE *p = list; p; p = next) {
next = p->next;
q[p->val] = enqueue(q[p->val], p);
}
NODE *result = cat(q[0], cat(q[1], q[2]));
// Now transform the circular queue to a simple linked list.
NODE *head = result->next;
result->next = NULL;
return head;
}
int main(void)
{
NODE *list = NULL;
int N = 100;
// Build a list of nodes for testing
for (int i = 0; i < N; ++i) {
NODE *p = malloc(sizeof(NODE));
p->val = rand() % 3;
p->data = N - i; // List ends up with data 1,2,3,..,N
p->next = list;
list = p;
}
list = sort012(list);
for (NODE *p = list; p; p = p->next)
printf("key val=%d, data=%d\n", p->val, p->data);
return 0;
}
This is now a complete simple test and it runs just fine.
This is untested. (I will try to test it if I get time.) But it ought to be at least very close to a solution.
Using a doubly linked list. If you have already implemented a linked list object and the related link list node object, and are able to traverse it in the forward direction it isn't a whole bunch more work to traverse in the reverse direction.
Assuming you have a Node object somewhat like:
public class Node
{
public Node Next;
public Object Value;
}
Then all you really need to do is change you Node class and you Insert method(s) up a little bit to keep track of of the Node that came previously:
public class Node
{
public Node Next;
public Node Previous;
public Object Value;
}
public void Insert(Node currentNode, Node insertedNode)
{
Node siblingNode = currentNode.Next;
insertedNode.Previous = currentNode;
insertedNode.Next = siblingNode;
if(siblingNode!= null)
siblingNode.previous = insertedNode;
currentNode.next = insertedNode;
}
PS Sorry, I didn't notice the edit that included the C++ stuff so it's more C#
Works for all cases by CHANGING NODES rather than NODE DATA.. Hoping its never too late!
METHOD(To throw some light on handling corner cases):
1. Keep three dummy nodes each for 0,1,2;
2. Iterate throught the list and add nodes to respective list.
3. Make the next of zero,one,two pointers as NULL.
4. Backup this last nodes of each list.
5. Now handle 8 different possible cases to join these list and Determine the HEAD.
zero one two
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
An implementation of this in C++.
Node* sortList(Node *head)
{
struct Node dummyzero,dummyone,dummytwo;
dummyzero.next = dummyone.next = dummytwo.next = NULL;
struct Node *zero =&dummyzero,*one = &dummyone,*two=&dummytwo;
Node *curr = head,*next=NULL;
while(curr)
{
next = curr->next;
if(curr->data==0)
{
zero->next = curr;
zero = zero->next;
}
else if(curr->data==1)
{
one->next = curr;
one = one->next;
}
else
{
two->next = curr;
two = two->next;
}
curr = next;
}
zero->next = one->next = two->next =NULL; //Since this dummynode, No segmentation fault here.
Node *zerolast = zero,*onelast = one,*twolast = two;
zero = dummyzero.next;
one = dummyone.next;
two = dummytwo.next;
if(zero==NULL)
{
if(one==NULL)
head = two;
else
{
head = one;
onelast->next = two;
}
}
else
{
head = zero;
if(one==NULL)
zerolast->next = two;
else
{
zerolast->next = one;
onelast->next = two;
}
}
return head;
}
The idea is to use dutch flag sorting algorithm, with a slight modification:
sort 0's and 1's as per dutch flag method,
But for 2's instead of adding them at the end of list, keep them in a separate linked list.
And finally append the 2's list to the sorted list of 0's and 1's.
Node * sort012_linked_list(Node * head) {
if (!head || !head->next)
return head;
Node * head_of_2s = NULL;
Node * prev = NULL;
Node * curr = head;
while (curr) {
if (curr->data == 0) {
if (prev == NULL || prev->data == 0) {
prev = curr;
curr = curr->next;
}
else {
prev->next = curr->next;
curr->next = head;
head = curr;
curr = prev->next;
}
}
else if (curr->data == 1) {
prev = curr;
curr = curr->next;
}
else { // curr->data == 2
if (prev == NULL) {
head = curr->next;
curr->next = head_of_2s;
head_of_2s = curr;
curr = head;
}
else {
prev->next = curr->next;
curr->next = head_of_2s;
head_of_2s = curr;
curr = prev->next;
}
}
}
if (prev)
prev->next = head_of_2s;
return head;
}

KD TREES (3-D) Nearest Neighbour Search

I am looking at the Wikipedia page for KD trees Nearest Neighbor Search.
The pseudo code given in Wikipedia works when the points are in 2-D(x,y) .
I want to know,what changes should i make,when the points are 3-D(x,y,z).
I googled a lot and even went through similar questions link in stack overflow ,but i did n't find the 3-d implementation any where,all previous question takes 2-D points as input ,not the 3-D points that i am looking for.
The pseudo code in Wiki for building the KD Tree is::
function kdtree (list of points pointList, int depth)
{
// Select axis based on depth so that axis cycles through all valid values
var int axis := depth mod k;
// Sort point list and choose median as pivot element
select median by axis from pointList;
// Create node and construct subtrees
var tree_node node;
node.location := median;
node.leftChild := kdtree(points in pointList before median, depth+1);
node.rightChild := kdtree(points in pointList after median, depth+1);
return node;
}
How to find the Nearest neighbor now after building the KD Trees?
Thanks!
You find the nearest neighbour exactly as described on the Wikipedia page under the heading "Nearest neighbour search". The description there applies in any number of dimensions. That is:
Go down the tree recursively from the root as if you're about to insert the point you're looking for the nearest neighbour of.
When you reach a leaf, note it as best-so-far.
On the way up the tree again, for each node as you meet it:
If it's closer than the best-so-far, update the best-so-far.
If the distance from best-so-far to the target point is greater than the distance from the target point to the splitting hyperplane at this node,
process the other child of the node too (using the same recursion).
I've recently coded up a KDTree for nearest neighbor search in 3-D space and ran into the same problems understand the NNS, particularly 3.2 of the wiki. I ended up using this algorithm which seems to work in all my tests:
Here is the initial leaf search:
public Collection<T> nearestNeighbourSearch(int K, T value) {
if (value==null) return null;
//Map used for results
TreeSet<KdNode> results = new TreeSet<KdNode>(new EuclideanComparator(value));
//Find the closest leaf node
KdNode prev = null;
KdNode node = root;
while (node!=null) {
if (KdNode.compareTo(node.depth, node.k, node.id, value)<0) {
//Greater
prev = node;
node = node.greater;
} else {
//Lesser
prev = node;
node = node.lesser;
}
}
KdNode leaf = prev;
if (leaf!=null) {
//Used to not re-examine nodes
Set<KdNode> examined = new HashSet<KdNode>();
//Go up the tree, looking for better solutions
node = leaf;
while (node!=null) {
//Search node
searchNode(value,node,K,results,examined);
node = node.parent;
}
}
//Load up the collection of the results
Collection<T> collection = new ArrayList<T>(K);
for (KdNode kdNode : results) {
collection.add((T)kdNode.id);
}
return collection;
}
Here is the recursive search which starts at the closest leaf node:
private static final <T extends KdTree.XYZPoint> void searchNode(T value, KdNode node, int K, TreeSet<KdNode> results, Set<KdNode> examined) {
examined.add(node);
//Search node
KdNode lastNode = null;
Double lastDistance = Double.MAX_VALUE;
if (results.size()>0) {
lastNode = results.last();
lastDistance = lastNode.id.euclideanDistance(value);
}
Double nodeDistance = node.id.euclideanDistance(value);
if (nodeDistance.compareTo(lastDistance)<0) {
if (results.size()==K && lastNode!=null) results.remove(lastNode);
results.add(node);
} else if (nodeDistance.equals(lastDistance)) {
results.add(node);
} else if (results.size()<K) {
results.add(node);
}
lastNode = results.last();
lastDistance = lastNode.id.euclideanDistance(value);
int axis = node.depth % node.k;
KdNode lesser = node.lesser;
KdNode greater = node.greater;
//Search children branches, if axis aligned distance is less than current distance
if (lesser!=null && !examined.contains(lesser)) {
examined.add(lesser);
double nodePoint = Double.MIN_VALUE;
double valuePlusDistance = Double.MIN_VALUE;
if (axis==X_AXIS) {
nodePoint = node.id.x;
valuePlusDistance = value.x-lastDistance;
} else if (axis==Y_AXIS) {
nodePoint = node.id.y;
valuePlusDistance = value.y-lastDistance;
} else {
nodePoint = node.id.z;
valuePlusDistance = value.z-lastDistance;
}
boolean lineIntersectsCube = ((valuePlusDistance<=nodePoint)?true:false);
//Continue down lesser branch
if (lineIntersectsCube) searchNode(value,lesser,K,results,examined);
}
if (greater!=null && !examined.contains(greater)) {
examined.add(greater);
double nodePoint = Double.MIN_VALUE;
double valuePlusDistance = Double.MIN_VALUE;
if (axis==X_AXIS) {
nodePoint = node.id.x;
valuePlusDistance = value.x+lastDistance;
} else if (axis==Y_AXIS) {
nodePoint = node.id.y;
valuePlusDistance = value.y+lastDistance;
} else {
nodePoint = node.id.z;
valuePlusDistance = value.z+lastDistance;
}
boolean lineIntersectsCube = ((valuePlusDistance>=nodePoint)?true:false);
//Continue down greater branch
if (lineIntersectsCube) searchNode(value,greater,K,results,examined);
}
}
The full java source can be found here.
I want to know,what changes should i make,when the points are
3-D(x,y,z).
You get the current axis on this line
var int axis := depth mod k;
Now depending on the axis, you find the median by comparing the corresponding property. Eg. if axis = 0 you compare against the x property. One way to implement this is to pass a comparator function in the routine that does the search.

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

Resources