This question already has answers here:
How do you validate a binary search tree?
(33 answers)
Closed 8 years ago.
i propose a recursive implementation for checking whether binary search tree is valid:
/*
Return true if binary tree is a binary search tree
*/
bool BinaryTree::isBinarySearchTree(BinaryTree* tree, int& prev)
{
if(!isBinarySearchTree(tree->left, tree->data)) // left
return false;
if(tree->value > prev) // here
return false;
else
prev = tree->value;
return isBinaryTree(tree->right); // right
}
i have big doubt on the second check,
if(tree->value > prev) // here
return false;
whats your favorite c++ implementation for this problem?
EDIT
how would you extend to find larger BST in given tree?
It's amazing how many people get this wrong.
Here's an example of a tree which the naive solution fails to reject:
5
/ \
/ \
4 6
/ \ / \
1 7 1 7
Every invocation of a naive check will succeed, since every parent is between its children. Yet, it is clearly not a well-formed binary search tree.
Here's a quick solution:
bool test(Tree* n,
int min=std::numeric_limits<int>::min(),
int max=std::numeric_limits<int>::max()) {
return !n || (
min < n->data && n->data < max
&& test(n->left, min, n->data)
&& test(n->right, n->data, max));
}
This isn't perfect, because it requires that neither INT_MIN nor INT_MAX be present in the tree. Often, BST nodes are ordered by <= instead of <, and making that change would only reserve one value instead of two. Fixing the whole thing is left as an exercise.
Here's a demonstration of how the naive test gets it wrong:
#include <iostream>
#include <limits>
#define T new_tree
struct Tree{
Tree* left;
int data;
Tree* right;
};
Tree* T(int v) { return new Tree{0, v, 0}; }
Tree* T(Tree* l, int v, Tree* r) { return new Tree{l, v, r}; }
bool naive_test(Tree* n) {
return n == 0 || ((n->left == 0 || n->data > n->left->data)
&& (n->right == 0 || n->data < n->right->data)
&& naive_test(n->left) && naive_test(n->right));
}
bool test(Tree* n,
int min=std::numeric_limits<int>::min(),
int max=std::numeric_limits<int>::max()) {
return !n || (
min < n->data && n->data < max
&& test(n->left, min, n->data)
&& test(n->right, n->data, max));
}
const char* goodbad(bool b) { return b ? "good" : "bad"; }
int main(int argc, char**argv) {
auto t = T( T( T(1),4,T(7)), 5, T(T(1),6,T(7)));
std::cerr << "Naive test says " << goodbad(naive_test(t))
<< "; Test says " << goodbad(test(t)) << std::endl;
return 0;
}
Recursive impelentation:
bool is_bst (node *root, int min = INT_MIN, int max = INT_MAX)
{
if (root)
{
// check min/max constaint
if (root->data <= min || root->data >= max)
return false;
if (root->left != NULL)
{
// check if the left node is bigger
// or if it is not BST tree itself
if (root->data < root->left->data ||
!is_bst (root->left, min, root->data))
return false;
}
if (root->right != NULL)
{
// check if the right node is smaller
// or if it is not BST tree itself
if (root->data > root->right->data ||
!is_bst (root->right, root->data, max))
return false;
}
}
return true;
}
Iterative impelentation
node_type curr = root;
node_type prev = null;
std::stack<node_type> stack;
while (1)
{
if(curr != null)
{
stack.push (curr);
curr = curr->left;
continue;
}
if(stack.empty()) // done
return true;
curr = stack.pop ();
if (prev != null)
{
if(curr->data < prev->data)
return false;
}
prev = curr;
curr = curr->right;
}
Related
I'm writing a program to print the largest prime in a binary search tree, this is my program:
bool isPrime(int number) {
bool is_prime = true;
if (number == 0 || number == 1)
is_prime = false;
for (int i = 2; i <= number / 2; i++)
{
if (number % i == 0) {
is_prime = false;
break;
}
}
return is_prime;
}
BSTNode* largestPrime(BSTNode* root)
{
BSTNode* temp = new BSTNode;
temp->data = 0;
if (root != nullptr) {
largestPrime(root->left);
if (isPrime(root->data) && temp->data < root->data)
temp->data = root->data;
largestPrime(root->right);
}
return temp;
}
But the output is always 0, I don't know how to fix this, can anyone help me solve this problem? Thanks for your help !
First change largestPrime to return an int. Don't know why you made it return a pointer.
Second, don't ignore the return values of the recursive calls to largestPrime. That should have been a red flag.
Something like this
int largestPrime(BSTNode* root)
{
int max = 0;
if (root != nullptr) {
int temp = largestPrime(root->left);
if (isPrime(temp) && max < temp)
max = temp;
if (isPrime(root->data) && max < root->data)
max = root->data;
temp = largestPrime(root->right);
if (isPrime(temp) && max < temp)
max = temp;
}
return max;
}
UPDATE
Here's a similar version that returns a pointer to the node containing the largest prime.
BSTNode* largestPrime(BSTNode* root)
{
BSTNode* max = nullptr;
if (root != nullptr) {
BSTNode* temp = largestPrime(root->left);
if (temp && isPrime(temp->data) && (max == nullptr || max->data < temp->data))
max = temp;
if (isPrime(root->data) && (max == nullptr || max < root->data))
max = root->data;
temp = largestPrime(root->right);
if (temp && isPrime(temp->data) && (max == nullptr || max->data < temp->data))
max = temp;
}
return max;
}
I'd start with isPrime to make it a little bit faster and easier to read:
bool isPrime(int number) {
if (number <= 1) return false; // negatives, 0 and 1 are not primes
if (number == 2) return true;
if ((number&1) == 0) return false; // even numbers are not primes, except 2
for (int i = 3; i <= number / 2; i+=2) // check only odd numbers
if (number % i == 0) return false;
return true;
}
next step is to fix largest prime search:
BSTNode* largestPrime(BSTNode* root)
{
if (root != nullptr) {
BSTNode* maxPrime = isPrime(root->data) ? root : nullptr;
BSTNode* maxLeftPrime = largestPrime(root->left);
if (maxLeftPrime != nullptr && (maxPrime == nullptr || maxLeftPrime->data > maxPrime->data))
maxPrime = maxLeftPrime;
BSTNode* maxRightPrime = largestPrime(root->right);
if (maxRightPrime != nullptr && (maxPrime == nullptr || maxRightPrime->data > maxPrime->data))
maxPrime = maxRightPrime;
return maxPrime;
}
return nullptr;
}
if you have actual binary search tree, where max(left->data) <= node->data <= max(right->data) then you can optimize function a little bit:
BSTNode* largestPrime(BSTNode* root)
{
if (root != nullptr) {
BSTNode* maxRightPrime = largestPrime(root->right);
if (maxRightPrime != nullptr) return maxRightPrime;
if (isPrime(root->data)) return root;
BSTNode* maxLeftPrime = largestPrime(root->left);
if (maxLeftPrime != nullptr) return maxLeftPrime;
}
return nullptr;
}
You should make use of the BST property: since an in-order traversal will visit its values in sorted order, you could do an inverse in-order traversal, and at the first prime you find you can exit the recursion and return it all the way to the initial caller. Because of the BST order, you know this will be the greatest prime in the tree.
BSTNode* largestPrime(BSTNode* root)
{
BSTNode* max = nullptr;
if (root != nullptr) {
BSTNode* temp = largestPrime(root->right);
if (temp != nullptr) // Found it in subtree, get out of here.
return temp;
if (isPrime(root->data))
return root; // Found it
return largestPrime(root->left); // Not found yet, try left
}
return nullptr; // No prime found
}
While working on a problem, I have tried the following solution. Somehow my output is stuck into infinite loop and not printing result or updated heap tree.
Given a tree where the left and right subtrees are min heaps, but the root node does not maintain the min heap property. Your code should modify the tree rooted at Node* n so it is a min heap. (This means you need to satisfy the min heap property:
it is okay for a node's value to be equal to one or both of its children, but the node's value must not be greater than either of its children. You do not have to try to balance the tree or make it a complete tree.)
#include <iostream>
#include <string>
You have the following class Node already defined.
You cannot change this class definition, so it is
shown here in a comment for your reference only:
class Node {
public:
int value;
Node *left, *right;
Node(int val = 0) { value = val; left = right = nullptr; }
~Node() {
delete left;
left = nullptr;
delete right;
right = nullptr;
}
};
This function has also previously been defined for you:
void printTreeVertical(const Node* n);
You can use it to print a verbose, vertical diagram of
a tree rooted at n. In this vertical format, a left child
is shown above a right child in the same column. If no
child exists, [null] is displayed.
*/
void downHeap(Node *n) {
Node *curr = new Node();
Node *mino = new Node();
if (n == nullptr ){
return;
} else if (n->left->value > n->value & n->right->value > n->value){
return;
// } else if (n->left== nullptr & n->right== nullptr) {
// return;
// }
} else {
// node* curr = new Node(n)
// n = new Node((std::min(n->left->value, n->right->value));
// if (n->left->value)
while(n->left!= nullptr & n->right!= nullptr){
if (n->left == nullptr){
mino = n->right;
} else if (n->right == nullptr) {
mino = n->left;
} else {
mino = (std::min(n->left, n->right));
}
std::cout << n->value << std::endl;
std::cout << mino->value << std::endl;
if(n->value > mino-> value){
curr->value = n->value;
n->value = mino->value;
mino->value = curr->value;
std::cout << n->value << std::endl;
std::cout << mino->value << std::endl;
downHeap(mino);
}
}
return;
}
}
// Implement downHeap() here.
// You can also use this compact printing function for debugging.
void printTree(Node *n) {
if (!n) return;
std::cout << n->value << "(";
printTree(n->left);
std::cout << ")(";
printTree(n->right);
std::cout << ")";
}
int main() {
Node *n = new Node(100);
n->left = new Node(1);
n->left->left = new Node(3);
n->right = new Node(2);
n->right->left = new Node(3);
n->right->right = new Node(4);
n->right->right->right = new Node(5);
std::cout << std::endl << "BEFORE - Vertical printout:" << std::endl;
printTreeVertical(n);
downHeap(n);
std::cout << "Compact printout:" << std::endl;
printTree(n);
std::cout << std::endl << " AFTER Vertical printout:" << std::endl;
printTreeVertical(n);
delete n;
n = nullptr;
return 0;
}
Please suggest what I am missing. I feel I am making it too complicated. Also, I do not have any other function like swap for converting the binary tree into heap min. I am not using an array or vector as well. So, if you can provide me simple solution I will appreciate it.
Your primary problem is this line of code:
mino = (std::min(n->left, n->right));
Here, you're comparing two pointers when you really want to compare the values in the two objects you're referring to, and return a pointer to the object that has the smaller value. That is:
mino = (n->left->value < n->right->value) ? n->left : n->right;
Also in this line of code:
} else if (n->left->value > n->value & n->right->value > n->value){
You probably want && (logical AND) rather than & (bitwise AND). See https://www.geeksforgeeks.org/what-are-the-differences-between-bitwise-and-logical-and-operators-in-cc/.
Finally, your code formatting is a little off so it's difficult to tell, but it looks like the return statement is outside the while loop in your downHeap function. If it is outside the loop body, then that could lead to an infinite loop.
This is the easiest solution I came up with.
Try this code for complete solution.
void downHeap(Node *n) {
// check if it is a leaf node
if (n->left == NULL && n->right == NULL) {
return;
}
if ((n->left != NULL) && (n->right != NULL)) {
if ((n->value <= n->left->value) && (n->value <= n->right->value)) {
return;
}
}
// Node passed in is not a leaf
// If left is null, we can focus on the right first
// If the right node has a greater value
if (n->right != NULL) {
if ((n->left == NULL) && (n->right->value < n->value)) {
int rightnodevalue = n->right->value;
int nodevalue = n->value;
n->value = rightnodevalue;
n->right->value = nodevalue;
if (n->right != NULL) {
downHeap(n->right);
return;
}
}
}
// Node passed in is not a leaf
// Left is not null
// First check if right is null
// If right is null, we can focus on the left first
// If the left node has a greater value
if (n->left != NULL) {
if ((n->right == NULL) && (n->left->value < n->value)) {
int leftnodevalue = n->left->value;
int nodevalue = n->value;
n->value = leftnodevalue;
n->left->value = nodevalue;
if (n->left != NULL) {
downHeap(n->left);
return;
}
}
}
// Node passed in is not a leaf
// Left is not null
// Right is not null
// If left is less than right
if ((n->left != NULL) && (n->right != NULL)) {
if (n->left->value < n->right->value) {
int leftnodevalue = n->left->value;
int nodevalue = n->value;
n->value = leftnodevalue;
n->left->value = nodevalue;
if (n->left != NULL) {
downHeap(n->left);
return;
}
}
else {
// Proceed to swap the parent and the right node
// Reference pointers for child's pointers
int rightnodevalue = n->right->value;
int nodevalue = n->value;
n->value = rightnodevalue;
n->right->value = nodevalue;
if (n->right != NULL) {
downHeap(n->right);
return;
}
}
}
return;
}
If you define a helper function to swap node values, you can make your code a lot cleaner and implement recursion quite easily. For example:
// DEFINE HELPER FUNCTION
void compareSwap(Node *a, Node *b) {
int temp;
if (a->value > b->value) {
temp = b->value;
b->value = a->value;
a->value = temp;
}
return;
}
void downHeap(Node *n) {
Node *compNode;
// 1. n is a leaf
if (!n->left && !n->right) {
return;
}
// 2. n has one left child
else if (n->left && !n->right) {
if (n->value > n->left->value) {
compareSwap(n, n->left);
downHeap(n->left);
}
return;
}
// 3. n has one right child
else if (!n->left && n->right) {
if (n->value > n->right->value) {
compareSwap(n, n->right);
downHeap(n->right);
}
return;
}
// 4. n has two children ... (n->left && n->right)
else {
// HEAP IS SATISFIED, RETURN NOTHING
if ((n->value <= n->left->value) && (n->value <= n->right->value)) {
return;
}
// RIGHT IS LESS THAN n BUT LEFT IS NOT, SWAP RIGHT
else if (((n->value <= n->left->value) && (n->value > n->right->value))) {
compareSwap(n, n->right);
downHeap(n->right);
return;
}
// LEFT IS LESS THAN n BUT RIGHT IS NOT, SWAP LEFT
else if (((n->value > n->left->value) && (n->value <= n->right->value))) {
compareSwap(n, n->left);
downHeap(n->left);
return;
}
// BOTH ARE LESS THAN, SWAP MIN
else {
compNode = (n->left->value < n->right->value) ? n->left : n->right;
compareSwap(n, compNode);
downHeap(compNode);
return;
}
}
}
I am implementing an AVL tree and my search and insertion functions work properly, but I get a segmentation fault with my remove function. I have implemented a BST tree correctly before, so I know the issue is with the rebalancing of the tree rather than the initial deletion of a node.
Since my insertion operation works with the rebalancing, I also know the issue is not with the rotation functions themselves.
I have tried different strategies such as maintaining a balance factor at each node and have tried implementing other source code I have found online but I always end up with a segmentation fault and really cannot find where. I'd appreciate any help.
class AVL
{
public:
AVL();
Node* insert(int num);
Node* search(int num);
Node* remove(int num);
void print();
void comparisonPrint();
private:
int comparisonCount;
Node* root;
int max(int a, int b);
int getHeight(Node* t);
int getBalance(Node* t);
Node* insert(Node* &t, int num);
Node* rotateWithLeftChild(Node* t);
Node* rotateWithRightChild(Node* t);
Node* doubleRotateWithLeftChild(Node* t);
Node* doubleRotateWithRightChild(Node* t);
Node* search(Node* t, int num);
Node* removeMin(Node* parent, Node* node);
Node* remove(Node* &t, int num);
void print(Node* t);
//print
};
int AVL::max(int a, int b)
{
return (a > b)? a : b;
}
int AVL::getHeight(Node* t)
{
return (t == NULL) ? 0 : t->height;
}
int AVL::getBalance(Node* t)
{
if(t == NULL)
return 0;
return getHeight(t->leftChild) - getHeight(t->rightChild);
}
//helper function for remove - finds min
Node* AVL::removeMin(Node* parent, Node* node) //removes node, but does not delete - returns ptr instead
{
if(node != NULL)
{
if(node->leftChild != NULL) //go to leftmost child in right subtree
return removeMin(node, node->leftChild);
else //min val
{
parent->leftChild = node->rightChild;
return node;
}
}
else //subtree empty - incorrect use of function
return NULL;
}
Node* AVL::remove(Node* &t, int num)
{
cout << num;
if(t != NULL)
{
if(num > t->key)
{
comparisonCount++;
remove(t->rightChild, num);
}
else if(num < t->key)
{
comparisonCount++;
remove(t->leftChild, num);
}
else if(t->leftChild != NULL && t->rightChild != NULL)
{
comparisonCount++;
//2 children
Node* minRightSubtree = removeMin(t, t->rightChild);
t->key = minRightSubtree->key;
delete minRightSubtree;
}
else
{
comparisonCount++;
//0 or 1 child
Node* temp = t;
if(t->leftChild != NULL)
t = t->leftChild;
else if(t->rightChild != NULL)
t = t->rightChild;
delete temp;
}
//update height
t->height = max(getHeight(t->leftChild), getHeight(t->rightChild)) + 1;
int balance = getBalance(t);
if(balance > 1 && getBalance(t->leftChild) >= 0)
return rotateWithRightChild(t);
if(balance > 1 && getBalance(t->leftChild) < 0)
{
t->leftChild = rotateWithLeftChild(t->leftChild);
return rotateWithRightChild(t);
}
if(balance < -1 && getBalance(t->rightChild) <= 0)
return rotateWithLeftChild(t);
if(balance < -1 && getBalance(t->rightChild) > 0)
{
t->rightChild = rotateWithRightChild(t->rightChild);
return rotateWithLeftChild(t);
}
}
return t;
}
So I need the remove function to remove a specified node and rebalance the tree when necessary using the appropriate rotations. However, I keep getting a segmentation fault whenever I try to call the function in my main. Thanks.
There are two problems with your code. First is the removeMin function and the else if part in remove function when the node to be deleted has two children.
Basic aim of the removeMin function should be to find the inorder successor of the node to be deleted which is t in your case. Consider the case when t has 2 children (both leaf nodes) then your removeMin function will set t->leftChild as t->rightChild->rightChild which is NULL which is wrong. Also the restructuring of the tree should be done inside remove hence removeMin becomes:
Node* AVL::removeMin(Node* node) // returns inorder successor of 't'
{
if(node->left == NULL)
return node;
return removeMin(node->left);
}
Coming to remove function, we reset t->key with minRightSubtree->key and the node to be deleted now is minRightSubtree. But notice that the order of keys has changed in the chain from node t till node minRightSubtree. t->key is less than all the keys of nodes till before minRightSubtree. Hence you cannot just delete minRightSubtree, you have to call remove function on the node minRightSubtree which will take care of restructuring this chain. Also you can get a little help from the recursion stack to get the correct child for the current node t after deletion/rotation:
Node* AVL::remove(Node* &t, int num)
{
if (t == NULL)
return NULL;
if (num > t->key)
t->rightChild = remove(t->rightChild, num);
else if (num < t->key)
t->leftChild = remove(t->leftChild, num);
else if (t->leftChild != NULL && t->rightChild != NULL)
{
//2 children
Node* minRightSubtree = removeMin(t->rightChild);
t->key = minRightSubtree->key;
t->rightChild = remove(t->rightChild, minRightSubtree->key);
}
else
{
//0 or 1 child
Node* temp = t;
if (t->leftChild != NULL)
t = t->leftChild;
else if (t->rightChild != NULL)
t = t->rightChild;
if(temp == t)
t = NULL;
delete temp;
}
if (t == NULL) // this case was added since there is a possibility of deleting 't'
return NULL;
//update height
t->height = max(getHeight(t->leftChild), getHeight(t->rightChild)) + 1;
int balance = getBalance(t);
if (balance > 1 && getBalance(t->leftChild) >= 0)
return rotateWithRightChild(t);
if (balance > 1 && getBalance(t->leftChild) < 0)
{
t->leftChild = rotateWithLeftChild(t->leftChild);
return rotateWithRightChild(t);
}
if (balance < -1 && getBalance(t->rightChild) <= 0)
return rotateWithLeftChild(t);
if (balance < -1 && getBalance(t->rightChild) > 0)
{
t->rightChild = rotateWithRightChild(t->rightChild);
return rotateWithLeftChild(t);
}
return t;
}
I'm assuming your code for updating heights and balancing the rooted sub-tree is correct since I've forgotten about it's theory and will need to revise.
I have written a function that returns true if given binary tree is binary search tree else returns false.
bool IsBst(node* root)
{
if(root->left == NULL && root->right == NULL)
{
return true;
}
if(root->left->data <= root->data && root->right->data > root->data)
{
return (IsBst(root->left) && IsBst(root->right))
}
else
{
else false;
}
}
Is my function right?
Will this function return right answer?
I have doubt in case of if left child is null then what will this comparison root->left->data<=root->data return?(If there is NULL)
Help me to improve this!
Thanks in advance!
It should be something like
bool IsBst(const node* root, node* minNode = nullptr, node* maxNode = nullptr)
{
if (root == nullptr) {
return true;
}
if (minNode != nullptr && root->data < minNode->data)
{
return false;
}
if (maxNode != nullptr && maxNode->data < root->data)
{
return false;
}
return IsBst(root->left, minNode, root)
&& IsBst(root->right, root, maxNode);
}
If you're using C++ 17 and above, you can do it even more elegantly by using an optional class. Hence, you don't need to do nullptr checks for min and max:
bool checkBST0(const Node* root, const std::optional<int>& min, const std::optional<int>& max) {
if (root != nullptr) {
const auto data = root->data;
if ((min.has_value() && min >= data) ||
(max.has_value() && max <= data)) {
return false;
}
std::optional<int> opt(data);
return checkBST0(root->left, min, opt) && checkBST0(root->right, opt, max);
}
return true;
}
Initially, you should call this method with an optional without any value:
std::optional<int> emptyOptional;
return checkBST0(root, emptyOptional, emptyOptional);
Nope, it's not right. It would fail on this tree:
3
\
\
5
And it would give a wrong answer on this one:
4
/ \
/ \
/ \
2 6
/ \ / \
1 9 0 8
A BST is defined as a tree, whose each internal node stores a key greater than all the keys in the node’s left subtree and less than those in its right subtree (see the Wikipedia article).
So it's not enough for a 1-2-9 left subtree in my example to have a left node value less than it's root (1<2) and the right node greater than it (9>2). It should also satisfy the condition that all its nodes have values less than 4, the value in the whole tree's root.
Here is an example in C I gave in the answer to the question Pseudo code to check if binary tree is a binary search tree - not sure about the recursion:
// Test a node against its closest left-side and right-side ancestors
boolean isNodeBST(NODE *lt, NODE *node, NODE *rt)
{
if(node == NULL)
return true;
if(lt != NULL && node->key <= lt->key)
return false;
if(rt != NULL && node->key >= rt->key)
return false;
return
isNodeBST(lt, node->left, node) &&
isNodeBST(node, node->right, rt);
}
boolean isTreeBST(TREE *tree)
{
return isNodeBST( NULL, tree->root, NULL);
}
So I tried my own solution in C++ but there is a bug in the code. That problem comes from judge.
So what I'm doing is keep adding a sum value and then check if the provided sum equals to the total sum in a leaf.
bool hasPathSum(TreeNode *root, int sum) {
stack<TreeNode*> st;
TreeNode *temp = root;
int SUM = 0;
bool hasSum = false;
st.push(temp);
while(!st.empty() && temp != NULL)
{
if(temp)
{
st.push(temp);
temp = temp->left;
}
else
{
st.pop();
temp = st.top();
SUM += temp->val;
if(SUM == sum)
hasSum = true;
temp = temp->right;
}
}
return hasSum;
}
Trivial to express recursively:
bool hasPathSum(TreeNode *node, int sum) {
if (!node) {
return sum == 0;
}
return hasPathSum(node->left, sum-node->val) ||
hasPathSum(node->right, sum-node->val);
}
If you translate this to a stack implementation, you will see some of the problems in yours. In particular, it is only at the leaves you want to check the sum (you check interior nodes). You have to adjust the sum as you go up and down the tree (you always add to it).
public static boolean hasPathSum(TreeNode node, int targetSum) {
if (node == null) return false;
targetSum-= node.val;
if (targetSum == 0 && node.left==null && node.right==null) {
return true;
}
int left = hasPathSum(node.left, targetSum);
int right = hasPathSum(node.right, targetSum;
return left || right;
}