Finding the kth smallest value in a BST - c

Here is what I have to find the kth smallest value in a binary search tree:
struct treeNode
{
int data;
struct treeNode *left, *right:
};
int rank(stuct treeNode* ptr, int k)
{
if(node == NULL)
return root;
while(ptr->left != NULL) {
ptr = ptr->left;
return rank(ptr->left)
}
}
This is obviously not correct. Without providing the solution, could someone guide me in the right direction as to how I could solve this? I am having trouble figuring out how I could find the kth smallest element in a BST.

A BST is a sorted binary tree, an in-order traversal (left subtree, current node, right subtree) will give sorted node values. To find the kth smallest node, just do an in-order traversal with a counter. The counter starts from 0, whenever a node is traversed, increase it by one, when it reaches k, the node is the kth smallest one.

If you have the sizes of each of the subtrees, this can be doable without having to read the data into an array (or otherwise traversing the tree) and counting up. If you don't keep the size information handy, you'll need a helper function to calculate the size.
The basic idea, figure out what is the index of the current node. If it is less than k, you need to search the left subtree. If it is greater than k, search the right offsetting the nodes counted from the left and current. Note that this is essentially the same as searching through a regular BST, except this time we are searching by index, not data. Some pseudocode:
if size of left subtree is equal to k:
// the current node is kth
return data of current node
else if size of left subtree is greater than k:
// the kth node is on the left
repeat on the left subtree
else if size of left subtree is less than k:
// the kth node is on the right
reduce k by the size of the left subtree + 1 // need to find the (k')th node on the right subtree
repeat on the right subtree
To illustrate, consider this tree with the marked indices (don't even worry about the data as it's not important in the search):
3
/ \
2 6
/ / \
0 4 7
\ \
1 5
Suppose we want to find the 2nd (k = 2).
Starting at 3, the size of the left subtree is 3.
It is greater than k so move to the left subtree.
The size of the left subtree is 2.
k is also 2 so the current node must be the 2nd.
Suppose we want to find the 4th (k = 4).
Starting at 3, the size of the left subtree is 3.
It is less than l so adjust the new k to be 0 (k' = 4 - (3 + 1)) and move to the right subtree.
Starting at 6, the size of the left subtree is 2.
It is greater than k' (0) so move to the left subtree.
The size of the left subtree is 0.
k' is also 0 so the current node must be the 4th.
You get the idea.

This should work:
int rank(struct treeNode* n,int k,int* chk)
{
if(!n) return -1;
int _chk = 0;
if(!chk) chk = &_chk;
int t = rank(n->left,k,chk);
if(t>=0) return t;
if(++*chk > k) return n->data;
int t = rank(n->right,k,chk);
if(t>=0) return t;
return -1;
}
call as rank(root,k,0)

Related

Find the index of the farthest smaller number in the right side of an array

Given an array of size N. For every element in the array, the task is to find the index of the farthest element in the array to the right which is smaller than the current element. If no such number exists then print -1
This question is taken from here
Sample Test Cases
Input
3, 1, 5, 2, 4
Output
3, -1, 4, -1, -1
Input
1, 2, 3, 4, 0
Output
4, 4, 4, 4, -1
I would also like to clarify that this is not a duplicate of this post here. While I did understand the solution mentioned in the post, I would really like to know why the above approach does not work for all test cases.
I came up with the following approach,
Create a binary search tree from the right side of the array
Each node stores the following info - the value, the index of the current element and the index of the smallest element which is farthest away from it's right side
While inserting, check if the current element being inserted (while moving to the right subtree) satisfies the condition and update the farthestDst accordingly
I tried to submit this, but I got Wrong Answer (failing test case not shown) despite running successfully against some sample test cases. I have attached my code in C++ below
class TreeNode{
public:
// farthestDst is the index of the smallest element which is farthest away from it's right side
int val,idx,farthestDst;
TreeNode* left;
TreeNode* right;
TreeNode(int value, int index, int dst){
val = value;
idx = index;
farthestDst = dst;
left = right = NULL;
}
};
class Solution{
public:
TreeNode* root = NULL;
unordered_map <int,TreeNode*> mp; // store address of each node just to speed up search
TreeNode* insertBST(TreeNode* root, int val, int idx, int dst){
if(root == NULL){
TreeNode* node = new TreeNode(val,idx,dst);
mp[val] = node;
return node;
}
else if(val >= root->val){ // checking the condition
if((root->idx)-idx > dst){
dst = root->idx;
}
root->right = insertBST(root->right,val,idx,dst);
}
else{
root->left = insertBST(root->left,val,idx,dst);
}
return root;
}
// actual function to complete where N is the size of the vector and nums contains the values
vector<int> farNumber(int N,vector<int> nums){
vector<int> res;
if(nums.size() == 0){ // base case check if nums is empty
return res;
}
for(int i = nums.size()-1; i >= 0; i--){
root = insertBST(root,nums[i],i,-1);
}
for(int i = 0; i < nums.size(); i++){
TreeNode* node = mp[nums[i]];
res.push_back(node->farthestDst);
}
return res;
}
};
Just a note, if anyone wants to test their solution, they can do so at this link
Please do let me know if further clarification about the code is needed
Any help would be appreciated. Thanks!
mp[] assumes that each element value appears at most once in the input. This is not given as part of the problem description, so it's not guaranteed. If some value appears more than once, its original value in mp[] will be overwritten. (Ironically, most C++ standard libraries implement unordered_map<T> as a balanced BST -- an AVL tree or red-black tree.)
Not technically a bug, but as pointed out by nice_dev in a comment, because your BST performs no rebalancing, it can become arbitrarily badly balanced, leading to O(n) insertion times for O(n^2) performance overall. This will occur on, e.g, sorted or reverse-sorted inputs. There are probably test cases large enough to cause timeouts for O(n^2)-time algorithms.
Unfortunately, adding rebalancing to your code to bring the worst-case time down to O(n log n) will cause it to become incorrect, because it currently depends on a delicate property: It doesn't compare each inserted element with all smaller-valued elements to its right, but only with the ones you encounter on the path down from the root of the BST. Whenever during this traversal you encounter an element at position j with value nums[j] < nums[i], you ignore all elements in its left subtree. With your current implementation, this is safe: Although these elements are all known to be smaller than nums[i] by the BST property, they can't be further to the right than j is, because insertion order means that every child is to the left of its parent. But if you change the algorithm to perform tree rotations to rebalance the tree, the second property can be lost -- you could miss some element at position k with nums[k] < nums[j] < nums[i] but k > j.
Finally, having both a member variable root and a function argument root is confusing.

Find the k-th smallest element recursively in a B-tree with more than one elements in a node

Suppose we have the following b-tree
I would like to create an algorithm in order to find the k-th smallest element. I tried to implement what was written in this link but I found out that none of the solutions seem to work for this kind of tree.
So far I have done this, which runs fine for the elements of the last branch
i <-0
function kthSmallestElement(Node node, int k)
if(branch[i] != NULL) then
size<-branch[i].size();
if(k < size) then
i++;
call the function recursively for new branch[i], k
else if(k > size) then
k-=size
i++;
call the function recursively for new branch[i], k
else if (k==size) then
print branch[i]->entry[k-1]
else
print brach[i-1]->entry[k-1]
end function
I have implemented the algorithm using C
#define MAX 4 /* maximum number of keys in node. */
#define MIN 2 /* minimum number of keys in node */
typedef int Key;
typedef struct {
Key key;
int value; /* values can be arbitrary */
} Treeentry;
typedef enum {FALSE, TRUE} Boolean;
typedef struct treenode Treenode;
struct treenode {
int count; /* denotes how many keys there are in the node */
/*
The entries at each node are kept in an array entry
and the pointers in an array branch
*/
Treeentry entry[MAX+1];
Treenode *branch[MAX+1];
};
int i = 0;
int size = 0;
void FindKthSmallestElement(Treenode *rootNode, int k){
if(branch[i] != NULL) //since the node has a child
size = branch[i] ->count;
if(k < size){
i++;
FindKthSmallestElement(branch[i], k);
}else if(k > size){
k-=size;
i++;
FindKthSmallestElement(branch[i], k);
}else if (k==size)
printf ("%d", branch[i]->entry[k-1].key);
else
printf ("%d", brach[i-1]->entry[k-1].key);
}
Could you please suggest what should I fix in this in order to have a valid output for every kth smallest element? I tend to believe that this problem cannot be solved recursively, since we have more than one entries in each node. Would be wise to make it a heap tree like in this link?
This problem can be solve recursively. All you need is for the function to return 2 things:
The k-th smallest key (or a pointer to it) if it has k or more keys.
The size of the tree if it has less than k keys.
The recursion occurs by calling the function on every subtree of the (root) node, consecutively, from the left-most to the right-most, and with different (decreasing) parameter k:
Let the original/current tree be R, starts recursion by calling the function on R's left-most subtree with the same k as R receives.
If calling the function on a subtree of R successfully returns the k-th smallest key, then that's the answer and return it.
If calling the function on some subtree T of R couldn't find the k-th smallest key, but instead returns a the size of T, say n (< k), then:
If T is the right-most subtree, then R has fewer than k items, returns the size of R (which would have been found by summing the sizes of all its subtrees and the number of keys in R's root).
If n == k-1, then the k-th smallest key is the key immediately to the right of T
If n < k-1, then recurse on the subtree S immediately to the right of T with argument k-n-1 (i.e., to find the (k-n-1)-th smallest key in S)
Obviously you'd have to take care of the terminal condition where a tree's root has no more subtree. Conceptually it may be more easily handled by allowing a NULL subtree, which contains 0 key.
Recursively visit every node and add to a list the k smallest elements of the current node. In the end sort it and get the k-th number.
You could also try comparing the 2 list and keeping the k smallest ones each time but i think it's gonna make the code look more complicated and will end up with roughly the same or worse speed but for sure less memory occupied.

How to traverse through n elements in a doubly linked list in C?

As the title suggests, I have to iterate through a doubly linked list. The only problem is that I have to iterate through "n" elements.
For example, if I'm given a list of, 1 3 2 2 1 1, I have to iterate left or right depending on the value I'm on so:
1 -> 3 -> 1 -> 1. I can move over the same value as the value in the list. Since I start at 1, I can move left or right 1 element (can only go right). When I land on 3 I can move left or right 3 elements etc.
while (temp->next != NULL) {
//traverse n elements left or right
}
If I always just had to traverse 1 elements at a time it's as easy as
temp = temp->next;
If someone could explain a strategy to traversing 'n' elements depending on the value of the node, that would be much appreciated.
edit: You can only go in the direction if there are enough elements in that direction. So in the case of 1 -> 3, you can only go 3 to the right after.
I think your question is to traverse through n elements, where n is the value of the current node.
The code would be like ~
int tr;
while (temp->next != NULL)
{
tr=temp->data; // temp->data holds the value of the current node.
Node *leftptr = temp, *rightptr = temp;
while(tr!=0 && rightptr!=NULL) //moves right side
{
rightptr = rightptr->next;
tr--;
}
tr=temp->data;
while(tr!=0 && leftptr!=NULL) //moves left side
{
leftptr = leftptr->prev;
tr--;
}
}
You can implement your algorithm and choose how to traverse, given both the traversal rules.

How to check whether a complete binary tree is value-balanced

How can I check whether a given complete binary tree represented by an array is a value balanced binary tree? By value-balanced I mean, if for each and every node, the sum of the integer values of nodes on the left-hand side is equal to the sum of values on the right-hand side. What is the C-like algorithm?
It's easy to find out the indices of the nodes having children. But I'm unable to develop the logic for computing the sum at each node recursively. The sum also needs to be computed in such a manner that the sum of all the nodes of the left subtree below a particular node will be equal to the right-handed counterpart of it and dig down below in a similar manner. How is it possible using an array?
You can do a post order traversal of the tree, that sums each subtree, and when back to the root (of each subtree), evaluates if the two subtrees have the same weight.
C-like Pseudo code:
res = 1; //global variable, can also be used as sending pointer to res instead
int verifySums(Node* root) {
if (root == null) return 0;
int leftSum = verifySums(getLeft(root));
int rightSum = verifySums(getRight(root));
if (leftSum != rightSum) res = 0;
return leftSum + rightSum + getValue(root);
}
Where
Node getLeft(Node*) is returning a pointer to a Node representing
the left child of the argument
Node getRight(Node*) is returning a pointer to a Node representing
the right child of the argument
int getValue(Node*) is returning the value of the given node
The idea is to do a post-order traversal that sums the value of all children to the left, get sum to the right and then:
Verify correctness - if it's not, the answer of the entire tree is no, and set it in res.
sum the two sums + current node, and return it back to parent.

Center of Binary Tree

How can we find center of a binary tree?
What shall be the most efficient algorithm. Though center of binary tree will be the mid point of the path corresponding to the diameter of tree. We can find the diameter of tree without actually knowing the path, is there any similar technique for finding center of binary tree?
If you know the diameter : D
and you know the max depth of the tree : M
then your center will be at the (M-(D/2)) th node(from the root) on the deepest path.(it might be M - (D-1)/2 depending on parity, you need to check yourself)
If you have more than on 1 paths from root to leaf with M nodes then the center is the root. (only true when the longest path goes through the root)
EDIT:
To answer your remark.
if it doesn't go through the root. Let's take the D/2th node on the diameter it will still be on the longest side of the diameter path (wich is in all the cases the longest path from root to leaf). and therefore M-D/2 still represent this point from the root.
Taking M-D/2nth from the root is the same as talking D/2nth from the leaf of the longest path.
Am I clear enough ? You might just want to draw it to check it .
You could calculate this in linear time O(N) by storing a list of the nodes that you have traversed if you are using a recursive method where you calculate the diameter by using the height of the tree (see this website here).
For instance, adapt the linear-time diameter function at the link I posted above so that you are also collecting a list of the nodes you have visited, and not just distance information. On each recursive call, you would select the list that went along with the longer traversed distance. The middle of the list that represented the diameter of the tree would be the "center" of the tree.
Your setup would look like the following:
typedef struct linked_list
{
tree_node* node;
linked_list* next;
} linked_list;
typedef struct list_pair
{
linked_list* tree_height;
linked_list* full_path;
} list_pair;
//some standard functions for working with the structure data-types
//they're not defined here for the sake of brevity
void back_insert_node(linked_list** tree, tree_node* add_node);
void front_insert_node(linked_list** tree, tree_node* add_node);
int list_length(linked_list* list);
void destroy_list(linked_list* list);
linked_list* copy_list(linked_list* list);
linked_list* append_list(linked_list* first, linked_list* second);
//main function for finding the diameter of the tree
list_pair diameter_path(tree_node* tree)
{
if (tree == NULL)
{
list_pair return_list_pair = {NULL, NULL};
return return_list_pair;
}
list_pair rhs = diameter_path(tree->right);
list_pair lhs = diameter_path(tree->left);
linked_list* highest_tree =
list_length(rhs.tree_height) > list_length(lhs.tree_height) ?
rhs.tree_height : lhs.tree_height;
linked_list* longest_path =
list_length(rhs.full_path) > list_length(lhs.full_path) ?
rhs.full_path : lhs.full_path;
//insert the current node onto the sub-branch with the highest height
//we need to make sure that the full-path, when appending the
//rhs and lhs trees, will read from left-to-right
if (highest_tree == rhs.tree_height)
front_insert_node(highest_tree, tree);
else
back_insert_node(highest_tree, tree);
//make temporary copies of the subtrees lists and append them to
//create a full path that represents a potential diameter of the tree
linked_list* temp_rhs = copy_list(rhs.tree_height);
linked_list* temp_lhs = copy_list(lhs.tree_height);
linked_list* appended_list = append_list(temp_lhs, temp_rhs);
longest_path =
list_length(appended_list) > list_length(longest_path) ?
appended_list : longest_path;
list_pair return_list_pair;
return_list_pair.tree_height = copy_list(highest_tree);
return_list_pair.full_path = copy_list(longest_path);
destroy_list(rhs.tree_height);
destroy_list(rhs.full_path);
destroy_list(lhs.tree_height);
destroy_list(lhs.full_path);
return return_list_pair;
}
Now the function returns a series of pointers in the full_path structure member that can be used to cycle though and find the middle-node which will be the "center" of the tree.
P.S. I understand that utilizing copying functions is not the fastest approach, but I wanted to be clearer rather than make something that was faster but had too much pointer-twiddling.
Optimized implementation: The above implementation can be optimized by calculating the
height in the same recursion rather than calling a height() separately.
/*The second parameter is to store the height of tree.
Initially, we need to pass a pointer to a location with value
as 0. So, function should be used as follows:
int height = 0;
struct node *root = SomeFunctionToMakeTree();
int diameter = diameterOpt(root, &height); */
int diameterOpt(struct node *root, int* height)
{
/* lh --> Height of left subtree
rh --> Height of right subtree */
int lh = 0, rh = 0;
/* ldiameter --> diameter of left subtree
rdiameter --> Diameter of right subtree */
int ldiameter = 0, rdiameter = 0;
if(root == NULL)
{
*height = 0;
return 0; /* diameter is also 0 */
}
/* Get the heights of left and right subtrees in lh and rh
And store the returned values in ldiameter and ldiameter */
ldiameter = diameterOpt(root->left, &lh);
rdiameter = diameterOpt(root->right, &rh);
/* Height of current node is max of heights of left and
right subtrees plus 1*/
*height = max(lh, rh) + 1;
return max(lh + rh + 1, max(ldiameter, rdiameter));
}
Time Complexity: O(n)

Resources