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
}
Related
So I wrote a Ranked self-balancing Binary Search Tree instead of using std::set. I was expecting it to work faster for getting rank of elements, but it seems to take more time than using std::set and iterating through to find rank. Is there any way to speed it up?
#include<bits/stdc++.h>
struct treeNode{
int data;
int leftsize; //for finding rank
int height; //for balancing during insertions and deletions
treeNode* left;
treeNode* right;
treeNode()
:data(NAN), leftsize(0), left(nullptr), right(nullptr){}
treeNode(int val, int lsize, int ht)
:data(val), leftsize(lsize), height(ht), left(nullptr), right(nullptr){}
};
int height(treeNode* node)
{
if(node == nullptr)
return 0;
return node->height;
}
int getBalance(treeNode* node)
{
if(node==nullptr)
return 0;
return height(node->left) - height(node->right);
}
int parseLeftSub(treeNode* node)
{
if(node == nullptr)
return 0;
int cnt = 1;
cnt += parseLeftSub(node->left);
cnt += parseLeftSub(node->right);
return cnt;
}
void printNode(treeNode* node)
{
if(node == nullptr)
return;
printNode(node->left);
std::cout << node->data << " " << node->leftsize << std::endl;
printNode(node->right);
}
treeNode* createNode(int val)
{
treeNode* node = new treeNode(val, 1, 1);
return node;
}
treeNode* createTree(std::vector<int>& a, int start, int end)
{
if(start>end)
return nullptr;
int mid = (start + end)/2;
treeNode* node = createNode(a[mid]);
node->left = createTree(a, start, mid-1);
node->right = createTree(a, mid+1, end);
node->leftsize += parseLeftSub(node->left);
return node;
}
treeNode* rightRotate(treeNode* y)
{
treeNode* x = y->left;
treeNode* T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = std::max(height(y->left),
height(y->right)) + 1;
x->height = std::max(height(x->left),
height(x->right)) + 1;
// Return new root
y->leftsize = parseLeftSub(y->left) + 1;
return x;
}
treeNode* leftRotate(treeNode* x)
{
treeNode* y = x->right;
treeNode* T2 = y->left;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = std::max(height(x->left),
height(x->right)) + 1;
y->height = std::max(height(y->left),
height(y->right)) + 1;
// Return new root
y->leftsize = parseLeftSub(y->left) + 1;
return y;
}
treeNode* insertNode(int val, treeNode* node)
{
if(node == nullptr)
return createNode(val);
if(val < node->data)
node->left = insertNode(val, node->left);
else if(val > node->data)
node->right = insertNode(val, node->right);
else
return node;
node->height = 1 + std::max(height(node->left), height(node->right));
node->leftsize = parseLeftSub(node->left) + 1;
int balance = getBalance(node);
if(balance > 1 && val < node->left->data)
return rightRotate(node);
else if(balance < -1 && val > node->right->data)
return leftRotate(node);
else if(balance > 1 && val > node->left->data)
{
node->left = leftRotate(node->left);
return rightRotate(node);
}
else if(balance < -1 && val < node->right->data)
{
node->right = rightRotate(node->right);
return leftRotate(node);
}
return node;
}
treeNode* searchNode(int val, treeNode* node)
{
if(node == nullptr)
return nullptr;
treeNode* foundNode = nullptr;
if(val == node->data)
return node;
else if(val < node->data)
foundNode = searchNode(val, node->left);
else
foundNode = searchNode(val, node->right);
return foundNode;
}
treeNode* findLowerBound(int val, treeNode* node)
{
if(node == nullptr)
return nullptr;
if(val == node->data)
return node;
else if(val>node->data)
{
return(findLowerBound(val, node->right));
}
treeNode* temp = findLowerBound(val, node->left);
if(temp != nullptr && temp->data >= val)
return temp;
else
return node;
}
treeNode* findUpperBound(int val, treeNode* node)
{
if(node == nullptr)
return nullptr;
if(val == node->data)
return node;
else if(val<node->data)
{
return(findUpperBound(val, node->left));
}
treeNode* temp = findUpperBound(val, node->right);
if(temp != nullptr && temp->data <= val)
return temp;
else
return node;
}
treeNode* findMinNode(treeNode* node)
{
if(node->left == nullptr)
return node;
return (findMinNode(node->left));
}
treeNode* deleteNode(int val, treeNode*& node)
{
if(node == nullptr)
return nullptr;
if(node->data > val)
node->left = deleteNode(val, node->left);
else if(node->data < val)
node->right = deleteNode(val, node->right);
else
{
if(node->left==nullptr && node->right==nullptr)
{
delete node;
node = nullptr;
}
else if(node->left==nullptr)
{
treeNode* temp = node;
node = node->right;
delete temp;
}
else if(node->right==nullptr)
{
treeNode* temp = node;
node = node->left;
delete temp;
}
else
{
treeNode* temp = findMinNode(node->right);
node->data = temp->data;
node->right = deleteNode(temp->data, node->right);
}
}
if (node == NULL)
return node;
node->leftsize = parseLeftSub(node->left) + 1;
node->height = 1 + std::max(height(node->left),
height(node->right));
int balance = getBalance(node);
if (balance > 1 &&
getBalance(node->left) >= 0)
return rightRotate(node);
if (balance > 1 &&
getBalance(node->left) < 0)
{
node->left = leftRotate(node->left);
return rightRotate(node);
}
if (balance < -1 &&
getBalance(node->right) <= 0)
return leftRotate(node);
if (balance < -1 &&
getBalance(node->right) > 0)
{
node->right = rightRotate(node->right);
return leftRotate(node);
}
return node;
}
int findRank(int val, treeNode* node)
{
int rank = node->leftsize;
if(node==nullptr)
{
return -1;
}
if(val<node->data)
{
rank -= node->leftsize;
rank += findRank(val, node->left);
}
else if(val>node->data)
{
rank += findRank(val, node->right);
}
return rank;
}
I know its quite a lot. Also can any other stl containers be used to find rank, insert and delete efficiently
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.
If I was asked about number of nodes in binary tree, it would be so easy but I am asked to count number of distinct nodes in binary tree like below.
There are two 12 values!
Number of nodes in binary tree algoritm is this:
struct Node {
string data;
struct Node *left;
struct Node *right;
};
int getNumberOfNodes(Node* node)
{
if (node != NULL)
return getNumberOfNodes(node->left) + 1 + getNumberOfNodes(node->right);
else
return 0;
}
But for unique values, it is too hard -_-
You can change your function adding a container to maintain the values you already encountered. The best container has been suggested in the comment std::set.
The new code would be:
int getNumberOfNodes(Node* node, std::set<string>& uniqueValues)
{
if (node != NULL)
{
int count = 0;
if ( uniqueValues.find( node->data ) == uniqueValues.end() )
{
count = 1;
uniqueValues.insert ( node->data );
}
return getNumberOfNodes(node->left,uniqueValues) + count + getNumberOfNodes(node->right,uniqueValues);
}
else
return 0;
}
Not so different from your code.
At the end the uniqueValues.size() will be equal to the returned int.
Clear the uniqueValues before calling the function.
int count_label(Node *root, int data)
{
int count_of_data = 0;
if(root == NULL)
return 0;
if(data == root->data)
count_of_data += 1;
if(data > root->data)
count_of_data += count_label(root->right,data);
else
count_of_data += count_label(root->left,data);
return count_of_data;
}
//--------------------------------------------------------
unsigned int unique_nodes(Node *root)
{
int count_u = 0;
if(root == NULL)
return 0;
if(count_label(root, root->data) == 1)
{
count_u += 1;
}
count_u += unique_nodes(root->left);
count_u += unique_nodes(root->right);
return count_u;
}
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;
}
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;
}