How binary search tree is created? - algorithm

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

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 represent a non binary tree and how to do LCA on that tree?

How are non binary trees typically represented? Trees where there is no limit to the number of children a node can have. Is it best to use a Adjacency Matrix or Adjacency List and just assume there will be no cycles, or do something similar to this question ->
How to implement a Non-Binary tree
and follow up question, when you have a n-ary tree (is that the correct name for them?) What's a good way to find the Least Common Ancestor for two given nodes/data values in that tree? All I can find are algorithms that deal with binary trees, like this one ->
static Node lca(Node root,int v1,int v2)
{
if (root == null || root.data == v1 || root.data == v2) {
return root;
}
Node left = lca(root.left, v1, v2);
Node right = lca(root.right, v1, v2);
if (left != null && right != null) {
return root;
}
return (left != null) ? left : right;
}
Adjacency matrix sounds like a bad idea, it will be very sparse (most cells will be empty). Usually for n-ary trees (yes that's how they are called) you just follow the same strategy as with the binary tree, the difference is that a binary tree would have 2 fields representing the left and right children:
class Node<T> {
T value;
Node<T> left;
Node<T> right;
}
Here you change those fields into a data structure like an array (static or dynamic):
class Node<T> {
T value;
List<Node<T>> children;
}
As for the LCA, are you planning on storing the parent pointer in the nodes? Are the values supposed to be a tree with unique values? Will the values be ordered in any way?
If no, but you can assume that the nodes are in the tree (although handling the other case is not that hard) then the LCA is very similar to what you've shown above. You just need to change the part where you get the Node left and Node right so that it traverses all children:
int count = 0;
Node<T> temp = null;
for(Node<T> child : root.children) {
Node<T> result = lca(child, v1, v2);
if(result != null) {
count++;
temp = result;
}
}
if(count == 2) {
return root;
}
return temp;
With parent pointers and/or storing the dept in each node we can do better but at a storage cost.

Computing rank of a node in a binary search tree

If each node in a binary search tree stores its weight (number of nodes in its subtree), what would be an efficient method to compute a rank of a given node (its index in the sorted list) as I search for it in the tree?
Start the rank at zero. As the binary search proceeds down from the root, add the sizes of all the left subtrees that the search skips by, including the left subtree of the found node.
I.e., when the search goes left (from parent to left child), it discovers no new values less than the searched item, so the rank stays the same. When it goes right, the parent plus all the nodes in the left subtree are less than the searched item, so add one plus the left subtree size. When it finds the searched item. any items in the left subtree of the node containing the item are less than it, so add this to the rank.
Putting this all together:
int rank_of(NODE *tree, int val) {
int rank = 0;
while (tree) {
if (val < tree->val) // move to left subtree
tree = tree->left;
else if (val > tree->val) {
rank += 1 + size(tree->left);
tree = tree->right;
}
else
return rank + size(tree->left);
}
return NOT_FOUND; // not found
}
This returns the zero-based rank. If you need 1-based then initialize rank to 1 instead of 0.
Since each node has a field storing its weight, the first you should implement a method call size() which return the number of nodes in a node's substree:
private int size(Node x)
{
if (x == null) return 0;
else return x.N;
}
then compute the rank of a given node is easy
public int rank(Node key)
{ return rank(key,root) }
private int rank(Node key,Node root)
{
if root == null
return 0;
int cmp = key.compareTo(root);
// key are smaller than root, then the rank in the whole tree
// is equal to the rank in the left subtree of the root.
if (cmp < 0) {
return rank(key, root.left)
}
//key are bigger than root,the the rank in the whole tree is equal
// to the size of subtree of the root plus 1 (the root) plus the rank
//in the right sub tree of the root.
else if(cmp > 0){
return size(root.left) + 1 + rank(key,root.right);
}
// key equals to the root, the rank is the size of left subtree of the root
else return size( root.left);
}
Depends on the BST implementation, but I believe you can solve it recursively.
public int rank(Key key){
return rank(root, key);
}
private int rank(Node n, Key key){
int count = 0;
if (n == null)return 0;
if (key.compareTo(n.key) > 0) count++;
return count + rank(n.left, key) + rank(n.right, key);
}

BST to LinkList and back to same BST

Since I could not find anything useful so I am here to ask my question:
How can we convert the BST to a In-order linklist, and back to "same" BST, without using any extra space.
What I have tried so far (still doing though): I tried Morris Traversal to link up to the next in-order successor,
but it is not able to connect for all the nodes, only working for the left subtree, and right subtree, not for the actual root of the tree.
Please suggest how can I convert Tree to Linked List and back to Same tree...
To store a tree in lists - you need at least two lists: one for pre-order traversal, and the other for in-order traversal.
Luckily - since the tree is a BST, the in-order traversal is just the sorted list.
So, you can store the pre-order traversal (You can try doing it in-place) and by sorting the elements in re-construction, you can get the in-order traversal.
This post discusses how to reconstruct a tree from the inorder and pre-order traversals of it.
Binary Search Tree to List:
subTreeToList(node)
if (node.hasLeft()) then subTreeToList(node.left, list)
list.add(node.Value)
if (node.hasRight()) subTreeToList(node.right, list)
end if
subTreeToList end
treeToList(tree)
subTreeToList(tree.root)
treeToList end
list <- new List()
treeToList(tree)
You need to implement the idea above into your solution, if you are working with object-oriented technologies, then list and trees should be data members, otherwise they should be passed to the functions as references.
You can build back your tree knowing that insertion in the tree looks like this:
Insert(tree, value)
if (tree.root is null) then
tree.createRoot(value)
else
node <- tree.root
while (((node.value < value) and (node.hasRight())) or ((node.value > value) and (node.hasLeft())))
if ((node.value < value) and (node.hasRight())) then node <- node.right()
else node <- node.left()
end if
while end
if (node.value > value) then node.createLeft(value)
else node.createRight(value)
end if
end if
insert end
You just have to traverse your list sequentially and call the function implemented based on my pseudo-code above. Good luck with your homework.
I think I found the solution myself: below is the complete Java implementation
The logic + pseudo Code is as below
[1] Find the left most node in the tree, that will be the head of the LinkList, store it in the class
Node HeadOfList = null;
findTheHeadOfInorderList (Node root)
{
Node curr = root;
while(curr.left != null)
curr = curr.left;
HeadOfList = curr; // Curr will hold the head of the list
}
[2] Do the reverse - inorder traversal of the tree to convert it to a LL on right pointer, and make sure the left pointer is always pointing to the parent of the node.
updateInorderSuccessor(Node root, Node inorderNext, Node parent)
{
if(root != null)
//Recursively call with the right child
updateInorderSuccessor(root.right, inorderNext, root);
// Update the in-order successor in right pointer
root.right = inorderNext;
inorderNext = root;
//Recursively call with the left child
updateInorderSuccessor(root.left, inorderNext, root);
// Update the parent in left pointer
root.left = parent;
}
}
[3] To convert it back :
Traverse the list and find the node with left pointer as null,
Make it the root, break the link of this root in the linklist and also from its children...
Now the link list is broken into two parts one for left Subtree and one for right subtree,
recursively find the roots in these two list and make them the left and right child, Please refer the function restoreBST()
Node restoreBST(Node head)
{
if(head == null || (head.left == null && head.right == null)) return root;
Node prev, root, right, curr;
curr = head;
// Traverse the list and find the node with left as null
while(curr != null)
{
if(curr.left == null)
{
// Found the root of this tree
root = curr;
// Save the head of the right list
right = curr.right;
// Detach the children of the root just found, these will be updated later as a part of the recursive solution
detachChildren(curr, head);
break;
}
prev = curr;
curr = curr.right;
}
// By now the root is found and the children of the root are detached from it.
// Now disconnect the right pointer based connection in the list for the root node, so that list is broken in to two list, one for left subtree and one for right subtree
prev.right = null;
root.right = null;
// Recursively call for left and right subtree
root.left = restoreBST(head);
root.right = restoreBST(right);
//now root points to its proper children, lets return the root
return root;
}
Logic to detach the children is simple : Iterate through the list and look for the nodes with left pointer equal to root.
private void detachChildren(AvlNode root, AvlNode head) {
AvlNode curr = head;
while(curr != null)
{
if(curr.left == root)
{
curr.left = null;
}
curr = curr.right;
}
}
Here is a recursive solution for BST to LL, hope you find it useful.
Node BSTtoLL(BST root) {
if(null == root) return null;
Node l = BSTtoLL(root.left);
Node r = BSTtoLL(root.right);
Node l1 = null;
if(null != l) {
l1 = l;
while(null != l.left) { l = l.left; }
l.left = root;
l.right = null;
}
if(null != r) {
root.left = r;
root.right = null;
}
if(null != l1) return l1;
return root;
}

Link Tree nodes at each level

Given a binary tree, how would you join the nodes at each level, left to right.
Say there are 5 nodes at level three, link all of them from left to right.
I don't need anybody to write code for this.. but just an efficient algorithm.
Thanks
Idea is:
1. Traverse tree with BFS.
2. When you do traversing, you're linking nodes on next level - if node has left and right node, you'll link left to right. If node has next node, then you link rightmost child of current node to leftmost child of next node.
public void BreadthFirstSearch(Action<Node> currentNodeAction)
{
Queue<Node> q = new Queue<Node>();
q.Enqueue(root);
while (q.Count != 0)
{
Node current = q.Dequeue();
if (currentNodeAction != null)
currentNodeAction(current);
if (current.left != null) q.Enqueue(current.left);
if (current.right != null) q.Enqueue(current.right);
}
}
private void Linker(Node node)
{
Link(node.left, node.right);
if (node.next != null)
Link(node.right ?? node.left, node.next.left ?? node.next.right);
}
private void Link(Node node1, Node node2)
{
if (node1 != null && node2 != null)
node1.next = node2;
}
public void LinkSameLevel()
{
BreadthFirstSearch(Linker);
}
Create a vector of linked lists.
Do a DFS keeping track of your level, and for each node you find, add it to the linked list of the level.
This will run in O(n) which is optimal.
Is this what you want to do?
This is not a direct answer to the question and may not be applicable based on your situation. But if you have control over the creation and maintenance of the binary tree, it would probably be more efficient to maintain the links while building/updating the tree.
If you kept both left and right pointers at each level, then it would be "simple" (always easy to say that word when someone else is doing the work) to maintain them. When inserting a new node at a given level, you know its direct siblings from the parent node information. You can adjust the left and right pointers for the three nodes involved (assuming not at the edge of the tree). Likewise, when removing a node, simply update the left and right pointers of the siblings of the node being removed. Change them to point to each other.
I agree with Thomas Ahle's answer if you want to make all of the row-lists at the same time. It seems that you are only interested in making the list for a one specific row.
Let's say you have a giant tree, but you only want to link the 5th row. There's clearly no point in accessing any node below the 5th row. So just do an early-terminated DFS. Unfortunately, you still have to run through all of the ancestors of every node in the list.
But here's the good news. If you have a perfect binary tree (where every single node branches exactly twice except for the last row) then the first row will have 1 one, the second 2, the third 4, the fourth 8 and the fifth 16. Thus there are more nodes on the last row (16) than all the previous put together (1 + 2 + 4 + 8 = 15), so searching through all of the ancestors is still just O(n), where n is the number of nodes in the row.
The worst case on the other hand would be to have the fifth row consist of a single node with a full binary tree above it. Then you still have to search through all 15 ancestors just to put that one node on the list.
So while this algorithm is really your only choice without modifying your data structure its efficiency relies entirely on how populated the row is compared to higher rows.
#include <queue>
struct Node {
Node *left;
Node *right;
Node *next;
};
/** Link all nodes of the same level in a binary tree. */
void link_level_nodes(Node *pRoot)
{
queue<Node*> q;
Node *prev; // Pointer to the revious node of the current level
Node *node;
int cnt; // Count of the nodes in the current level
int cntnext; // Count of the nodes in the next level
if(NULL == pRoot)
return;
q.push(pRoot);
cnt = 1;
cntnext = 0;
prev = NULL;
while (!q.empty()) {
node = q.front();
q.pop();
/* Add the left and the right nodes of the current node to the queue
and increment the counter of nodes at the next level.
*/
if (node->left){
q.push(node->left);
cntnext++;
}
if (node->right){
q.push(node->right);
cntnext++;
}
/* Link the previous node of the current level to this node */
if (prev)
prev->next = node;
/* Se the previous node to the current */
prev = node;
cnt--;
if (0 == cnt) { // if this is the last node of the current level
cnt = cntnext;
cntnext = 0;
prev = NULL;
}
}
}
What I usually do to solve this problem is that I do a simple inorder traversal.
I initialize my tree with a constructor that gives a level or column value to every node. Hence my head is at Level 0.
public Node(int d)
{
head=this;
data=d;
left=null;
right=null;
level=0;
}
Now, if in the traversal, I take a left or a right, I simply do the traversal with a level indicator. For each level identifier, I make a Linked List, possibly in a Vector of Nodes.
Different approaches can be used to solve this problem. Some of them that comes to mind are -
1) Using level order traversal or BFS.
We can modify queue entries to contain level of nodes.So queue node will contain a pointer to a tree node and an integer level. When we deque a node we can check the level of dequeued node if it is same we can set right pointer to point to it.
Time complexity for this method would be O(n).
2) If we have complete binary tree we can extend Pre-Order traversal. In this method we shall set right pointer of parent before the children.
Time complexity for this method would be O(n).
3) In case of incomplete binary tree we can modify method (2) by traversing first root then right pointer and then left so we can make sure that all nodes at level i have the right pointer set, before the level i+1 nodes.
Time complexity for this method would be O(n^2).
private class Node
{
public readonly Node Left;
public readonly Node Right;
public Node Link { get; private set; }
public void Run()
{
LinkNext = null;
}
private Node LinkNext
{
get
{
return Link == null ? null : (Link.Left ?? Link.Right ?? Link.LinkNext);
}
set
{
Link = value;
if (Right != null)
Right.LinkNext = LinkNext;
if (Left != null)
Left.LinkNext = Right ?? LinkNext;
}
}
}
Keep a depth array while breadth-first search.
vector<forward_list<index_t>> level_link(MAX_NODES);
index_t fringe_depth = 0;
static index_t depth[MAX_NODES];
memset(depth,0,sizeof(depth));
depth[0] = 0;
Now when the depth-changes while de-queuing, you get all linked !
explored[0] = true;
static deque<index_t> fringe;
fringe.clear();
fringe.push_back(0); // start bfs from node 0
while(!fringe.empty()) {
index_t xindex = fringe.front();
fringe.pop_front();
if(fringe_depth < depth[xindex]) {
// play with prev-level-data
fringe_depth = depth[xindex];
}
Now we have fringe-depth, so we can level-link.
level_link[fringe_depth].push_front(xindex);
for(auto yindex : nodes[xindex].connected) {
if(explored[yindex])
continue;
explored[yindex] = true;
depth[yindex] = depth[xindex] + 1;
fringe.push_back(yindex);
}
}

Resources