Fastest non-recursive implementation of LCA? - algorithm

Here's the algorithm I came up with for non-recursively finding the lowest common ancestor of two nodes in a binary tree. Here's the basic strategy:
Use a dictionary/hashtable to store the tree. Each key-value pair represents a node and its parent.
Starting from each of the two nodes, walk up the tree by setting the variable representing each node's value to that of its parent, storing traversed values in a hashset (one for each of the two nodes).
The search is complete when any of the following conditions are reached: (a) the value of the two nodes is equal; or (b) when the two paths cross each other (i.e., the hashset of node 1's traversed values contains the current value for node 2, or vice versa); or (c) the node passed in doesn't exist in the tree (in which case the algorithm terminates and returns -1).
My understanding is that the worst-case time and space complexity of my algorithm is O(log(n)), since we never need to make more than 2 * height traversals or store more than 2 * height values in our hashsets (and since the lookup time for the hashsets and the tree dictionary are O(1)).
Following is my code (C#). Please advise if I am correct in my analysis, or if there is a more efficient (non-recursive) way to do this:
int LowestCommonAncestor(int value1, int value2, Dictionary<int, int> tree)
{
var value1Visited = new HashSet<int>();
var value2Visited = new HashSet<int>();
while (true)
{
if (value1 == value2) return value1;
if (value1Visited.Contains(value2)) return value2;
if (value2Visited.Contains(value1)) return value1;
int nextValue1;
int nextValue2;
if (tree.TryGetValue(value1, out nextValue1))
{
//Walk node 1 up the tree:
value1 = nextValue1;
value1Visited.Add(value1);
}
else
{
//Node doesn't exist in tree:
return -1;
}
if (tree.TryGetValue(value2, out nextValue2))
{
//Walk node 2 up the tree:
value2 = nextValue2;
value2Visited.Add(value2);
}
else
{
//Node doesn't exist in tree:
return -1;
}
}
}

Go up from each node to the root to measure its depth
Move up the path from the deeper node until you get to the same depth as the shallower one.
Move up the paths from both nodes (i.e., keeping the same depth on both paths) until they meet.

You don't need two hash sets.
Go up and collect in a single hash set the ancestors of one node
Go up from the second node and at each of its ancestors, check if the path collected at step 1 contains the current ancestor of the second. Stop at the first common one.
With D being the max depth of the tree, the complexity is O(D) worst-case complexity.
The worst case complexity in N - number of nodes - when the tree is degenerated in a list, one of the node being the head of this list and the other is the tail.
If the tree is balanced, D=log(N) - with log's base being the number of descendents of a node (binary - log2, ternary - log3, etc).

Here, then, is my revised algorithm:
int LCA(int value1, int value2, Dictionary<int, int> tree)
{
if (!tree.ContainsKey(value1) || !(tree.ContainsKey(value2))) return -1;
int depth1 = 0;
int depth2 = 0;
int tmpVal1 = value1;
int tmpVal2 = value2;
while (tmpVal1 != -1)
{
tmpVal1 = tree[tmpVal1];
depth1++;
}
while (tmpVal2 != -1)
{
tmpVal2 = tree[tmpVal2];
depth2++;
}
if (depth1 > depth2)
{
while (depth1 > depth2)
{
value1 = tree[value1];
depth1--;
}
}
else if (depth2 > depth1)
{
while (depth2 > depth1)
{
value2 = tree[value2];
depth2--;
}
}
while (value1 != value2)
{
value1 = tree[value1];
value2 = tree[value2];
}
return value1;
}

Related

BST - interval deletion/multiple nodes deletion

Suppose I have a binary search tree in which I'm supposed to insert N unique-numbered keys in the order given to me on standard input, then I am to delete all nodes with keys in interval I = [min,max] and also all connections adjacent to these nodes. This gives me a lot of smaller trees that I am to merge together in a particular way. More precise description of the problem:
Given a BST, which contains distinct keys, and interval I, the interval deletion works in two phases. During the first phase it removes all nodes whose key is in I and all edges adjacent to the removed nodes. Let the resulting graph contain k connected components T1,...,Tk. Each of the components is a BST where the root is the node with the smallest depth among all nodes of this component in the original BST. We assume that the sequence of trees Ti is sorted so that for each i < j all keys in Ti are smaller than keys in Tj. During the second phase, trees Ti are merged together to form one BST. We denote this operation by Merge(T1,...,Tk). Its output is defined recurrently as follows:
EDIT: I am also supposed to delete any edge that connects nodes, that are separated by the given interval, meaning in example 2 the edge connecting nodes 10 and 20 is deleted because the interval[13,15] is 'in between them' thus separating them.
For an empty sequence of trees, Merge() gives an empty BST.
For a one-element sequence containing a tree T, Merge(T) = T.
For a sequence of trees T1,...,Tk where k > 1, let A1< A2< ... < An be the sequence of keys stored in the union of all trees T1,...,Tk, sorted in ascending order. Moreover, let m = ⌊(1+k)/2⌋ and let Ts be the tree which contains Am. Then, Merge(T1,...,Tk) gives a tree T created by merging three trees Ts, TL = Merge(T1,...,Ts-1) and TR = Merge(Ts+1,...,Tk). These trees are merged by establishing the following two links: TL is appended as the left subtree of the node storing the minimal key of Ts and TR is appended as the right subtree of the node storing the maximal key of Ts.
After I do this my task is to find the depth D of the resulting merged tree and the number of nodes in depth D-1. My program should be finished in few seconds even for a tree of 100000s of nodes (4th example).
My problem is that I haven't got a clue on how to do this or where even start. I managed to construct the desired tree before deletion but that's about that.
I'd be grateful for implementation of a program to solve this or any advice at all. Preferably in some C-ish programming language.
examples:
input(first number is number of keys to be inserted in the empty tree, the second are the unique keys to be inserted in the order given, the third line containts two numbers meaning the interval to be deleted):
13
10 5 8 6 9 7 20 15 22 13 17 16 18
8 16
correct output of the program: 3 3 , first number being the depth D, the second number of nodes in depth D-1
input:
13
10 5 8 6 9 7 20 15 22 13 17 16 18
13 15
correct output: 4 3
pictures of the two examples
example 3: https://justpaste.it/1du6l
correct output: 13 6
example 4: link
correct output: 58 9
This is a big answer, I'll talk at high-level.Please examine the source for details, or ask in comment for clarification.
Global Variables :
vector<Node*> roots : To store roots of all new trees.
map<Node*,int> smap : for each new tree, stores it's size
vector<int> prefix : prefix sum of roots vector, for easy binary search in merge
Functions:
inorder : find size of a BST (all calls combinedly O(N))
delInterval : Main theme is,if root isn't within interval, both of it's childs might be roots of new trees. The last two if checks for that special edge in your edit. Do this for every node, post-order. (O(N))
merge : Merge all new roots positioned at start to end index in roots. First we find the total members of new tree in total (using prefix-sum of roots i.e prefix). mid denotes m in your question. ind is the index of root that contains mid-th node, we retrieve that in root variable. Now recursively build left/right subtree and add them in left/right most node. O(N) complexity.
traverse: in level map, compute the number of nodes for every depth of tree. (O(N.logN), unordered_map will turn it O(N))
Now the code (Don't panic!!!):
#include <bits/stdc++.h>
using namespace std;
int N = 12;
struct Node
{
Node* parent=NULL,*left=NULL,*right = NULL;
int value;
Node(int x,Node* par=NULL) {value = x;parent = par;}
};
void insert(Node* root,int x){
if(x<root->value){
if(root->left) insert(root->left,x);
else root->left = new Node(x,root);
}
else{
if(root->right) insert(root->right,x);
else root->right = new Node(x,root);
}
}
int inorder(Node* root){
if(root==NULL) return 0;
int l = inorder(root->left);
return l+1+inorder(root->right);
}
vector<Node*> roots;
map<Node*,int> smap;
vector<int> prefix;
Node* delInterval(Node* root,int x,int y){
if(root==NULL) return NULL;
root->left = delInterval(root->left,x,y);
root->right = delInterval(root->right,x,y);
if(root->value<=y && root->value>=x){
if(root->left) roots.push_back(root->left);
if(root->right) roots.push_back(root->right);
return NULL;
}
if(root->value<x && root->right && root->right->value>y) {
roots.push_back(root->right);
root->right = NULL;
}
if(root->value>y && root->left && root->left->value<x) {
roots.push_back(root->left);
root->left = NULL;
}
return root;
}
Node* merge(int start,int end){
if(start>end) return NULL;
if(start==end) return roots[start];
int total = prefix[end] - (start>0?prefix[start-1]:0);//make sure u get this line
int mid = (total+1)/2 + (start>0?prefix[start-1]:0); //or this won't make sense
int ind = lower_bound(prefix.begin(),prefix.end(),mid) - prefix.begin();
Node* root = roots[ind];
Node* TL = merge(start,ind-1);
Node* TR = merge(ind+1,end);
Node* temp = root;
while(temp->left) temp = temp->left;
temp->left = TL;
temp = root;
while(temp->right) temp = temp->right;
temp->right = TR;
return root;
}
void traverse(Node* root,int depth,map<int, int>& level){
if(!root) return;
level[depth]++;
traverse(root->left,depth+1,level);
traverse(root->right,depth+1,level);
}
int main(){
srand(time(NULL));
cin>>N;
int* arr = new int[N],start,end;
for(int i=0;i<N;i++) cin>>arr[i];
cin>>start>>end;
Node* tree = new Node(arr[0]); //Building initial tree
for(int i=1;i<N;i++) {insert(tree,arr[i]);}
Node* x = delInterval(tree,start,end); //deleting the interval
if(x) roots.push_back(x);
//sort the disconnected roots, and find their size
sort(roots.begin(),roots.end(),[](Node* r,Node* v){return r->value<v->value;});
for(auto& r:roots) {smap[r] = inorder(r);}
prefix.resize(roots.size()); //prefix sum root sizes, to cheaply find 'root' in merge
prefix[0] = smap[roots[0]];
for(int i=1;i<roots.size();i++) prefix[i]= smap[roots[i]]+prefix[i-1];
Node* root = merge(0,roots.size()-1); //merge all trees
map<int, int> level; //key=depth, value = no of nodes in depth
traverse(root,0,level); //find number of nodes in each depth
int depth = level.rbegin()->first; //access last element's key i.e total depth
int at_depth_1 = level[depth-1]; //no of nodes before
cout<<depth<<" "<<at_depth_1<<endl; //hoorray
return 0;
}

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 to find lowest common ancestor of a nary tree?

Is there a way without using extra space to find LCA of nary tree.
I did it using a string saving the preorder of both the nodes and finding common prefix
If nodes "know" their depth - or you're willing to allow the space to compute the depth of your nodes, you can back up from the lower node to the same depth of the higher node, and then go up one level at a time until they meet.
Depends on what "extra space" means in this context. You can do it with one integer - the difference in depths of the two nodes. Is that too much space?
Another possibility is given you don't have a parent pointer, you can use pointer reversal - every time you traverse a pointer, remember the location from which you came, remember the pointer you will next traverse, and then just before the next pointer traversal, replace that pointer with the back pointer. You have to reverse this when going up the tree to restore it. This takes the space of one pointer as a temporary. And another integer to keep the depth as you work your way down and up. Do this synchronously for the two nodes you seek, so that you can work your way back up from the lower one until you're at the same height in both traversals, and then work back up from both until you're at the common node. This takes three extra pieces of memory - one for each of the current depths, one for the temporary used during a pointer reversal. Very space efficient. Is it worth it?
Go back and do it for a binary tree. If you can do it for a binary tree you can do it for an n-ary tree.
Here's a link to LCA in a binary tree:
And here's how it looks after converting it to a n-ary tree LCA:
public class LCA {
public static <V> Node<V>
lowestCommonAncestor(Node<V> argRoot, Node<V> a, Node<V> b) {
if (argRoot == null) {
return null;
}
if (argRoot.equals(a) || argRoot.equals(b)) {
// if at least one matched, no need to continue
// this is the LCA for this root
return argRoot;
}
Iterator<Node<V>> it = argRoot.childIterator();
// nr of branches that a or b are on,
// could be max 2 (considering unique nodes)
int i = 0;
Node<V> lastFoundLCA = null;
while (it.hasNext()) {
Node<V> node = lowestCommonAncestor(it.next(), a, b);
if (node != null) {
lastFoundLCA = node;
i++ ;
}
if (i >= 2) {
return argRoot;
}
}
return lastFoundLCA;
}
}
Do a synchronous walk to both the nodes.
Start with LCA=root;
loop:
find the step to take for A and the step for B
if these are equal { LCA= the step; decend A; descend B; goto loop; }
done: LCA now contains the lca for A and B
Pseudocode in C:
struct node {
struct node *offspring[1234];
int payload;
};
/* compare function returning the slot in which this should be found/placed */
int find_index (struct node *par, struct node *this);
struct node *lca(struct node *root, struct node *one, struct node *two)
{
struct node *lca;
int idx1,idx2;
for (lca=root; lca; lca=lca->offspring[idx1] ) {
idx1 = find_index(lca, one);
idx2 = find_index(lca, two);
if (idx1 != idx2 || idx1 < 0) break;
if (lca->offspring[idx1] == NULL) break;
}
return lca;
}

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

algorithm to use to return a specific range of nodes in a directed graph

I have a class Graph with two lists types namely nodes and edges
I have a function
List<int> GetNodesInRange(Graph graph, int Range)
when I get these parameters I need an algorithm that will go through the graph and return the list of nodes only as deep (the level) as the range.
The algorithm should be able to accommodate large number of nodes and large ranges.
Atop this, should I use a similar function
List<int> GetNodesInRange(Graph graph, int Range, int selected)
I want to be able to search outwards from it, to the number of nodes outwards (range) specified.
alt text http://www.freeimagehosting.net/uploads/b110ccba58.png
So in the first function, should I pass the nodes and require a range of say 2, I expect the results to return the nodes shown in the blue box.
The other function, if I pass the nodes as in the graph with a range of 1 and it starts at node 5, I want it to return the list of nodes that satisfy this criteria (placed in the orange box)
What you need seems to be simply a depth-limited breadth-first search or depth-first search, with an option of ignoring edge directionality.
Here's a recursive definition that may help you:
I'm the only one of range 1 from myself.
I know who my immediate neighbors are.
If N > 1, then those of range N from myself are
The union of all that is of range N-1 from my neighbors
It should be a recursive function, that finds neighbours of the selected, then finds neighbours of each neighbour until range is 0. DFS search something like that:
List<int> GetNodesInRange(Graph graph, int Range, int selected){
var result = new List<int>();
result.Add( selected );
if (Range > 0){
foreach ( int neighbour in GetNeighbours( graph, selected ) ){
result.AddRange( GetNodesInRange(graph, Range-1, neighbour) );
}
}
return result;
}
You should also check for cycles, if they are possible. This code is for tree structure.
// get all the nodes that are within Range distance of the root node of graph
Set<int> GetNodesInRange(Graph graph, int Range)
{
Set<int> out = new Set<int>();
GetNodesInRange(graph.root, int Range, out);
return out;
}
// get all the nodes that are within Range successor distance of node
// accepted nodes are placed in out
void GetNodesInRange(Node node, int Range, Set<int> out)
{
boolean alreadyVisited = out.add(node.value);
if (alreadyVisited) return;
if (Range == 0) return;
// for each successor node
{
GetNodesInRange(successor, Range-1, out);
}
}
// get all the nodes that are within Range distance of selected node in graph
Set<int> GetNodesInRange(Graph graph, int Range, int selected)
{
Set<int> out = new Set<int>();
GetNodesInRange(graph, Range, selected, out);
return out;
}
// get all the nodes that are successors of node and within Range distance
// of selected node
// accepted nodes are placed in out
// returns distance to selected node
int GetNodesInRange(Node node, int Range, int selected, Set<int> out)
{
if (node.value == selected)
{
GetNodesInRange(node, Range-1, out);
return 1;
}
else
{
int shortestDistance = Range + 1;
// for each successor node
{
int distance = GetNodesInRange(successor, Range, selected, out);
if (distance < shortestDistance) shortestDistance = distance;
}
if (shortestDistance <= Range)
{
out.add(node.value);
}
return shortestDistance + 1;
}
}
I modified your requirements somewhat to return a Set rather than a List.
The GetNodesInRange(Graph, int, int) method will not handle graphs that contain cycles. This can be overcome by maintaining a collection of nodes that have already been visited. The GetNodesInRange(Graph, int) method makes use of the fact that the out set is a collection of visited nodes to overcome cycles.
Note: This has not been tested in any way.

Resources