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

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.

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.

How do you find the lowest key in a maximum sum path of a binary search tree in O(n)?

I am already calculating the maximum path sum, but i want to figure out which is the lowest key inside the path. How should i get this information? I am having troubles because if i check for the minimum inside the maximum path sum, i dont get what i am looking for (ofcourse) because im recurring firstly to the lowest element inside the BST.
Below what i tried:
int Max_Path_Sum(struct node* root){
int res= INT_MIN;
int min = INT_MAX;
Max_Path_Sum_Util( root, &res, &min);
printf("%d\n\n%d", min,res);
return res;
}
int Max_Path_Sum_Util(struct node* root, int *res, int *min){
if(root == NULL) return 0;
if( root->left == NULL && root->right == NULL)return root->key;
int ls = Max_Path_Sum_Util(root->left ,res , min);
int rs = Max_Path_Sum_Util(root->right ,res , min);
if(root->left != NULL && root->right != NULL){
*res = max(*res , ls + rs + root->key);
return max(ls,rs)+ root->key;
}
int sum = (root->left == NULL) ? rs+root->key : ls+root->key;
if(root != NULL && *min> root->key)*min = root->key;
return sum;
}
I am recieving the lowest key inside of the BST but i understand why it isnt the real result, beside some rare cases. My BST isnt balanced(its just an homework) So insterting keys without caring about balance.
struct node *root=New_Node(4);
Insert(root, 2);
Insert(root, 1);
Insert(root, 3);
Insert(root, 6);
Insert(root, 5);
Insert(root, 4);
Insert(root, -5);
Insert(root,0);
Insert( root, 3);
Insert(root, 2);
Using this tree the result of maximum path sum is 24, which should be correct.
As minimum i recieve 6, which isnt the right answer. I think it should be 2.
I am having troubles because if i check for the minimum inside the
maximum path sum, i dont get what i am looking for (ofcourse) because
im recurring firstly to the lowest element inside the BST.
I'd characterize the issue differently: you cannot directly record the minimum node along the path, because you don't know during any particular execution of the recursive function whether it is operating on a node that will turn out to be on the maximum path. But this genuine issue presents an actual problem only for some implementations.
When searching for a path in a tree via an algorithm that works one node at a time, you generally have two cases to consider as you process each node:
the path of interest passes through the current node, or
it doesn't
Specific algorithms generally subdivide those further. In particular, your recursive approach that processes the tree from the chosen root node toward the leaf nodes has these more specific cases to account for:
the path passes through the current node from its parent node (either ending at this node or continuing through exactly one of its children)
the path passes through this node and does not contain its parent node (it may also pass through one or both of its children)
the path does not pass through this node, but it is contained in the subtree rooted at this node
the path does not pass through any node in the subtree rooted at the current node
When processing a given node during your recursive traversal, you need to provide an answer as if that node were the root of the tree (because it might be), and also sufficient information for the answer to be determined correctly if it isn't.
Now note that neither the maximum path sum in a tree T1 nor the minimum element along that maximum path directly informs computation of those properties for a larger tree T2 that contains T1 as a subtree. You can't just add maximum path sums from a node's left and right subtrees -- that gives the right answer only in the case that in each subtree, the maximum path starts at the subtree root, so that you can join them together through their common parent to form a path. If the maximum path in one of the subtrees does not contain the subtree root or the subtree root is somewhere in the middle of the maximum path, then you can't form a path by joining the parent node to it.
Thus you need separate sets of information about each subtree:
information about the general maximum-sum path within that subtree, and
information about the maximum-sum path within it that starts at the subtree root (even if, as will be common, its path sum is less than the maximum in the subtree)
When processing a node, you can combine the latter sets of information about the subtrees rooted at its children to compute both sets of information for node under consideration. Moreover, you need to maintain data separation so that information applying to one of a node's child trees is not lost when you process the other. So what does that look like?
Let's first introduce another data structure to make it easier to keep track:
struct path_info {
int sum;
int min_value;
};
Now let's consider what your recursive function's signature needs to look like. There are several ways it could be done, but I'm going to suggest this:
struct path_info compute_max_path(struct node *root, struct path_info *max_leg)
The return value conveys the result for the tree rooted at the specified node, and the information needed to build such a result for a larger tree is conveyed via the max_leg output parameter.
I don't intend to write a complete solution for you, but I suspect there is one more idea that you're missing: how to segregate max_leg results for the subtrees. The key here is that when you recurse, you do not forward the max_leg parameter to the recursive calls. Instead, you declare new objects, and pass pointers to those:
struct path_info left_leg;
struct path_info left_result = compute_max_path(root->left, &left_leg);
struct path_info right_leg;
struct path_info right result = compute_max_path(root->right, &right_leg);
You then have all the information you need to set the max_leg data for the current node and to compute and return the maximum path information for its subtree.

Find maximum subtree in the given BST such that it has no duplicates

Given the BST which allows duplicates as separate vertices, how do I find the highest subtree such that it has no duplicates.
This is the idea:
(1) Check if the root value appears in its right subtree (inserting this way: left < root <= right). If not, tree has no duplicates. I look for it always on the left from the root's child.
(2) Traversing and doing (1) I can find all subtrees without duplicates, storing their root pointer and height.
(3) Comparing heights I can find largest seeked subtree.
I don't know how to store these information while traversing. I found programs for finding all duplicate subtrees of BST that use hash maps, but if possible I would prefer to avoid using hash maps, as I haven't had them on my course yet.
<!-- language: lang-c -->
typedef struct vertex {
int data;
struct vertex *left;
struct vertex *right;
} vertex, *pvertex;
// Utility functions
int Height(pvertex t){
if (t == NULL)
return 0;
if (Height(t->left) > Height(t->right))
return Height(t->left) + 1;
else
return Height(t->right) + 1;
}
int DoesItOccur(pvertex t, int k){
if(!t)
return 0;
if(t->data==k)
return 1;
if(t->data<k){
return DoesItOccur(t->left,k);
}
}
// My function
pvertex MaxSeeked(pvertex t){
if(!t)
return NULL;
if(DoesItOccur(t->right,t->data)==0)
return t;
else if{
if(t->left && t->right){
if(Height(MaxSeeked(t->left))>Height(MaxSeeked(t->right)))
return t->left;
else
return t->right;
}
}
else if{
......
}
}
I don't know how to store these information while traversing. I found programs for finding all duplicate subtrees of BST that use hash maps, but if possible I would prefer to avoid using hash maps, as I haven't had them on my course yet.
Note in the first place that you only need to track all the subtrees of the maximal height discovered so far. Or maybe you can limit that to just one such, if that's all you need to discover. For efficiency, you should also track what that maximal height actually is.
I'll suppose that you must not add members to your node structure, but if you could do, you could add a member or two wherein to record whether the tree rooted at each node contains any dupes, and how high that tree is. You could populate those data as you go, and remember what the maximum height is, then make a second traversal to collect the nodes.
But without modifying any nodes themselves, you can still track the current candidates by other means, such as a linked list. And you can put whatever metadata you want into the tracking data structure. For example,
struct nondupe_subtree {
struct vertex *root;
int height;
struct nondupe_subtree *next;
};
You can then, say, perform a selective traversal of your tree in breadth first order, carrying along a linked list of struct nondupe_subtree nodes:
Start by visiting the root node.
Test the subtree rooted at each visited node to see whether it contains any dupes, according to the procedure you have described.
If so then enqueue its children for traversal.
If not then measure the subtree height and update your linked list (or not) accordingly. Do not enqueue this node's children.
When no more nodes are enqueued for traversal, you linked list contains the roots of all the maximal height subtrees without dupes.
Note that that algorithm would in many cases be significantly sped if you could compute and store all the subtree heights in an initial DFS pass, for it is otherwise prone to performing duplicate tree-height computations. Many of them, in some cases.
Note also that although it does simplify this particular algorithm, your rule for always putting dupes to the right works against balanced trees, which may also yield reduced performance. In the worst case, where are vertices are duplicate, your "tree" will perforce be linear.

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.

Should Binary Heap be a binary tree or linked list?

I have an assignment to implement a binary heap. However, I'm not sure whether I should implement the binary heap as a binary tree data structure or a simple double linked list.
If I should implement as a binary tree, how should I keep track of the last element of the tree in order to insert a new element? In linked list that would be much easier.
So, does binary heap have to be a binary tree? If yes, how to track the last element?
Note: In my assignment there is a statement like this:
But you will implement the binary heap not as an array, but
as a tree.
To be more clear this is my node:
struct Word{
char * word;
int count;
struct Word * parent;
struct Word * left_child;
struct Word * right_child;
}
Solution taken from the question.
by #Yunus Eren Güzel
SOLVED:
After five hours of study I have found a way to implement heap as a pointer based tree.
The insertion algorithm is :
insert
node = create_a_node
parent = get_the_last_parent
node->parent = parent
if parent->left==NULL
parent->left=node
else
parent->right=node
end insert
get_last_parent parent,&height
height++
if parent->left==NULL || parent->right==NULL
return parent;
else
int left_height=0,right_height=0;
left = get_last_parent(parent->left,&left_height)
right = get_last_parent(parent->right,&right_height)
if left_height == right_height
height += right_height
return right
else if left_height > right_height
height += left_height
return left
end get_last_parent
A binary heap is, by definition, a binary tree. One way of implementing this in C is to store the tree elements in an array where the array index corresponds to the tree element (numbering the root node 0, its left child 1, its right child 2, and so on). You can then just store the size of the heap (initialized to 0 upon creation and incremented whenever an element is added) and use that to find the next open location.
For basic data structures questions like this, Wikipedia is your friend.
You should implement it as a tree. It will be easy and interesting. Heap has only property that any node has value less than or equal to its parent, if it is a max heap.
In array implementation we impose some more conditions.
If you need help about specific function implementation then you can ask it.
You need to travel down to add new node
call it with root, value to be inserted
insert(node, x){
if(node->value >= x)
//insert
if(node->left == 0)
node->left = new Node(x);
else if(node->right == 0)
node->right = new Node(x);
else if(node->left->value >= x)
insert(node->left, x);
else if(node->right->value >= x)
insert(node->right, x);
else
//insert between node and its any one child
insertBW(node, node->left, x);
else //if x is less than node value
//insert between node and its parent
insertBW(node->parent, node, x)
}
insertBW(p, c) is a function which insets a node containing value x between p and c
(I didn't tested this code please check for errors)
insertBW(Node* p, Node* c, T x)
{
Node* newnode = new Node(x);
newNode.x = x;
if(p == 0) //if node c is root
{
newnode.left = Tree.root.left;
Tree.root = newnode;
}
else
{
newnode.parent = p;
newnode.child = c;
if(p.left == c)
{
p.left = newnode;
}
else p.right = newnode;
}
}
This to me really seems to be a homework question & it seems you have not done any R&D on your own before asking (sorry for bit harsh words):)
In computer science, a heap is a specialized tree-based data structure that satisfies the heap property: if B is a child node of A, then key(A) ≥ key(B).
I think your teacher wants you to implement a priority queue data structure and that's where you are talking about both a Linked List and Heap together in the same question. Priority Queue can be implemented as a Heap or a Linked List where in to extract elements based on priority either you have to maintain elements sorted in case of linked list where say a maximum or minimum element goes at the front based upon whether you are implementing a max heap or a min heap OR priority queue can be implemented simply as a heap data structure.
Coming to the last point where you say "But you will implement the binary heap not as an array, but as a tree.", seems to be very irrelevant. Please do check again as to what is required or reproduce the exact question that has been asked in your assignment.
To put it simply, regarding your first question - no. A heap can be anything (array, linked list, tree, and when one must improvise a family of fluffy kittens). Note the definition of a heap: If "B" is a child of "A" then val(A) >= val(B) (or, in case of a min-heap, val(A) <= val(B)).
It's most common to refer to it as a tree (and also implement it as such) because it's easy to think of it as a tree. Also, the time-complexity & performance are good.
Regarding your second question, you gave no information, so as far as I know a solution that searches every node is as good as any other...
For any better answer, more information is required (what limitations do you have, what operations should you support, etc...)
A binary heap can be anything i.e. array, linked list, tree, etc. We just have to keep the right algorithm on how can you can access the data. For example, if you want to make it to the left child you can do this by 2N + 1(For starting index 0) where N is the parent index or the right child by 2N + 2. For the last element, you can initialise the heap with a variable count and increment it by 1 every time you insert a new element, this way you can keep track of the last element (Same for delete, just some modification has to be made on the collection).

Resources