I am writing a method to check if a given tree is a BST using the inorder traversal method. On executing this method, I get a segfault. Can someone help me correct it?
here, maximum stores the largest value in the BST, and k is initialized to 0. The BST is assumed to have unique positive values. isNull(root) checks if the current node is a null node or not.
bool check(BstNode* root)
{
if (root->data==maximum) return true;
isNull(root);
check(root->left);
if (root->data>k)
{
k=root->data;
}
else
{
return false;
}
check(root->right);
}
Every time when you call check(root->left) and check(root->right), I suppose you need to add sth to determine the left and the right branch is null or not. In your code, you just assume that there is sth in left and right branch and call the check function. I think that's the main reason.
You shouldn't need to specify the maximum value. An elegant solution can be found here
There are two approaches you can do this.
One is top-down approach, first check if current node is valid, if so, then check two subtree. This is very intuitive. you can find the code from #lerman's post:
struct TreeNode {
int data;
TreeNode *left;
TreeNode *right;
};
bool isBST(TreeNode *node, int minData, int maxData) {
if(node == NULL) return true;
if(node->data < minData || node->data > maxData) return false;
return isBST(node->left, minData, node->data) && isBST(node->right, node->data, maxData);
}
if(isBST(root, INT_MIN, INT_MAX)) {
puts("This is a BST.");
} else {
puts("This is NOT a BST!");
}
The other way is a bottom-up approach: first check left substree then right substree and check current tree at last. below is the code for this approach.
bool isValidBST(TreeNode *root) {
int mmin, mmax;
return helper(root, mmin, mmax);
}
bool helper(TreeNode* root, int& mmin, int& mmax) {
if(!root) {
mmin = INT_MAX;
mmax = INT_MIN;
return true;
}
int leftmin, leftmax, rightmin, rightmax;
if(!helper(root->left, leftmin, leftmax))
return false;
if(!helper(root->right, rightmin, rightmax))
return false;
if(root->val > leftmax && root->val < rightmin) {
mmin = min(min(leftmin, rightmin), root->val);
mmax = max(max(leftmax, rightmax), root->val);
return true;
}
else
return false;
}
You might notice that the first approach is pre-order traversal and the second approach is post-order traversal. inorder traversal in inappropriate here because it conflicts with the definition of BST.
Related
Here is my code, but it is not producing any output.
stack < int > st;
bool func(Node * root) {
if (root != NULL) {
func(root -> left);
st.push(root -> data);
func(root -> right);
}
while (!st.empty()) {
int upar = st.top();
st.pop();
if (upar > st.top()) {
continue;
} else {
return 0;
}
}
return 1;
}
Please tell me what am I missing. I traced the code right but it is not showing the relevant result.
What I see from your code is that your function func() is called recursively but its return value is never checked. It should be fine if it means to push stuff into a stack to create an in-order traversal, but you also included the while loop to check if the data are in ascending order. This is the problem.
The easiest fix I can think of is to break it into two:
stack < int > st;
void func(Node * root) {
if (root != NULL) {
func(root -> left);
st.push(root -> data);
func(root -> right);
}
}
bool check(Node* root) {
func(root);
while (!st.empty()) {
int upar = st.top();
st.pop();
if (upar > st.top()) {
continue;
} else {
return 0;
}
}
return 1;
}
but you have to check are you going to assume no duplicate entries in the BST, for you're using upar > st.top() instead of >=.
If you insist to combine the two into one function, you can consider to change func() to pass on upper or lower bound for the values in addition to the Node* so you can correspondingly check the left and right sub-tree. You can skip the use of stack all together in this case. But start with the root node and bound from negative infinity to positive infinity. When you do the recursion, you replace the root->data for upperbound on left tree and for lowerbound on right tree.
I have to complete a function that will return true if a "tree" has a node that points back to itself or if a node has descendants that point back to it. The tree has at most one of these loops for every call.
struct Node
{
Node* left;
Node* right;
int data;
}
bool finder(Node* root, vector<Node*> cd) // helper
{
for (unsigned int i = 0; i < cd.size(); i++)
if (cd[i] == root) return true;
return false;
}
bool Looper(Node* root, vector<Node*> cd)//finder will be called to compare
the next node against the visited nodes.
{
returns false;
}
I know I need to traverse the tree and mark each node by putting it in the vector, but I have no idea what traversal to do or how to do it. Any ideas?
Potential solution:
bool Looper(Node* root, vector<Node*> cd){
vector<Node*> visited;
if(finder(root,visited))
return true;
if(root==nullptr)
returnvalue = false;
if(!finder(root,visited))
{
visited.push_back(root);
return Looper(root->left,visited);
return Looper(root->right,visited);
}
return false;
}
#include <iostream>
#include <vector>
struct Node
{
// some other stuff...
int id;
std::vector<Node*> children;
};
bool finder(Node* root, Node* currentNode, std::vector<bool>& visited)
{
visited[currentNode->id] = true;
for (Node* node : currentNode->children)
if (node == root)
{
std::cout << currentNode->id << '\n';
return true;
}
else if (!visited[node->id] && finder(root, node, visited))
{
return true;
}
visited[currentNode->id] = false;
return false;
}
bool Looper(Node* root, int n)
{
std::vector<bool> visited(n, false);
return finder(root, root, visited);
}
int main()
{
Node n0{ 0 };
Node n1{ 1 };
Node n2{ 2 };
Node n3{ 3 };
n0.children.push_back(&n1);
n0.children.push_back(&n2);
n1.children.push_back(&n3);
n3.children.push_back(&n0);
if (Looper(&n0, 4))
std::cout << "Found\n";
}
Output:
3
Found
Since you want a child node that points to a parent, your tree will contain cycles. So you have to keep track of which nodes you've visited. That's why I keep track of the visited nodes. also I would recommend using std::vector to represent the tree instead of using nodes.
Here's my understanding of your task, simply call check_for_cycles with your tree's root node and an empty vector to detect a cycle in your tree.
bool check_for_cycles(Node* node, vector<Node*>& visited)
{
// null is a not a cycle
if (node == nullptr)
return false;
// have we been here before? if so we have a cycle
if (find(visited.begin(), visited.end(), node) != visited.end())
return true;
// mark this node as visited
visited.push_back(node);
// recursively check the sub trees
return check_for_cycles(node->left, visited) || check_for_cycles(node->right, visited);
}
Note a vector isn't the best choice for visited because of the time cost of checking if a node is present. An unordered_map would be better, and so would having a field in the node itself that you could mark.
This is untested code.
Could someone please let me know why my code isn't working? I am trying to count the number of times a given value appears in a binary tree using recursion. However, this approach is not working. I'd really appreciate some feedback and insight. Thank you.
public int valCount(int val) {
if (root == null) {
return 0;
}
return valCount(val, *root);
}
public int valCount(int val, Node *root) {
int cnt = 0;
if (root->left != null) {
if (root->data == val) {
cnt++;
}
int leftValCount = valCount(val, root->left);
}
if (root->right != null) {
if (root->data == val) {
cnt++;
}
int rightValCount = valCount(val, root->right);
}
return cnt + leftValCount + rightValCount;
}
A common mistake in recursion is to worry about stack frames other than the current one. Let the recursion do that work for you. Following this rule-of-thumb makes the code much easier to reason about.
The algorithm is simple: for each node, return 1 if the current node matches the target value else 0 if it doesn't and add the results of calling the same function on the left and right subtrees. The base case is when the function is called with a null root, return 0.
int valCount(int val, Node *root) {
if (!root) return 0;
return (root->val == val ? 1 : 0) +
valCount(val, root->left) +
valCount(val, root->right);
}
Can someone tell me why is this not working?
This seems correct to me
please someone look into this.
I am not able to find my mistake.
bool checkbst(node* root,int minValue,int maxValue)
{
if(root==NULL)
{
return true;
}
else if(((root->data)>(minValue))&&
((root->data)>(maxValue))&&
(checkbst(root->left,minValue,root->data))&&
(checkbst(root->right,root->data,maxValue)))
{
return true;
}
else
{
return false;
}
}
void isbst(node* root)
{
if( checkbst(root,INT_MIN,INT_MAX))
{
cout<<"the tree is bst";
}
}
You have a typo in checkbst, you are checking
((root->data)>(minValue))&&((root->data)>(maxValue))
while it probably should be
((root->data)>(minValue))&&((root->data)<(maxValue))
(notice the "less than" sign).
Your code verifies that the keys are inside a range, but it does not verify if the children satisfy the bst condition respect to the root. That is, the keys in the left subtree must be lesser than the root and the keys in the right one greater. You should check if the children are not null before doing any comparison involving subtrees.
This version should work:
bool checkbst(node* root, int minValue,int maxValue)
{
if (root == nullptr)
return true;
if (not (root->data >= minValue && root->data <= maxvalue))
return false;
if (root->left)
{
if (root->data < root->left->data)
if (not checkbst(root->left, minValue, maxValue))
return false;
else
return false;
}
// here the left subtree has been checked
if (root->right)
{
if (root->data < root->right->data)
return checkbst(root->right, minValue, maxValue);
else
return false;
}
return true; // everything is ok
}
I have checked your there is a small mistake code but there is a better way to do it. You just have to do the in order traversal of the given tree and store it in a array and then check if the elements in the array are sorted. If the elements are sorted then its a binary search tree else it will be a binary tree (which is a kind of basic difference between a binary tree and binary search tree).
There is a small mistake in your code
((root->data)>(maxValue))
should be
((root->data)<(maxValue))
Here is a solution that is O(n) time complexity and O(1) space. It uses in-order tree traversal to confirm that the tree is sorted according to BST rules, but it does not rely on maintaining an auxiliary array of in-order traversed Nodes. However, because it does rely on recursion it's usage of the stack (i.e. stack depth) can reach O(logn).
struct Node
{
int data;
struct Node* left;
struct Node* right;
};
bool isBSTHelper(Node* root, int& min, int& max)
{
if (nullptr == root)
{
max = numeric_limits<int>::min(); // has meaning for LHS traversal.
min = numeric_limits<int>::max(); // has meaning for RHS traversal.
return true;
}
int lhsMax;
int lhsMin;
if (!isBSTHelper(root->left, lhsMin, lhsMax) ||
lhsMax >= root->data)
{
return false;
}
int rhsMax;
int rhsMin;
if (!isBSTHelper(root->right, rhsMin, rhsMax) ||
rhsMin <= root->data)
{
return false;
}
min = std::min(lhsMin, root->data);
max = std::max(rhsMax, root->data);
return true;
}
bool isBST(Node* root)
{
int min;
int max;
return isBSTHelper(root, min, max);
}
I have to check if a tree is a binary search tree. I'm doing this with an inorder traversal with a temporary array that collects the values. I have to check if the array is ascending order and if it is then I return true:
bool myisBST(Node* node, std::vector<int> v);
bool myisBST(Node* node)
{
return myisBST(node, std::vector<int>());
}
bool myisBST(Node* node, std::vector<int> v)
{
if (node)
{
if (node->left)
return myisBST(node->left, v);
v.push_back(node->data);
if (node->right)
return myisBST(node->right, v);
}
return std::is_sorted(v.begin(), v.end());
}
When binary tree is this:
50
/ \
25 75
/ \ / \
1 12 62 -99
As you can see, the -99 makes this not a binary search tree, but it is still returning true. Is there something wrong with my implementation?
Demo
Two problems:
In myisBST, you are passing v by value, not by reference, so when you pass the vector on recursively, the changes that are made to it don't change its value in the calling method. Simply change the function signature to bool myisBST(Node* node, std::vector<int>& v) to fix this.
The value you should be returning is whether the vector is sorted (as you do in the last line of your method), but instead you are returning prematurely by writing return myisBST(node->left, v); and return myisBST(node->right, v);. You're not actually interested in the return values of these methods; you're just using them to fill the vector inorder. Remove the return from both of these lines.
Following these two fixes, your method works.
First of all, you should probably pass the vector by reference or each recursive call will get a copy and thus the original vector will probably be empty.
Second, you don't even need to create the vector first and then do the check, you can just check the BST property at each node, i.e., the root must be bigger than the left child and smaller than the right child, e.g.,
bool isBST(const Node* root, vector<int>* v) {
if (!root) { return true; }
bool leftBST = true;
if (root->left) {
if (root->data > root->left->data) {
leftBST = isBST(root->left, v);
} else {
// the current node violates the BST precondition
return false;
}
}
// push the root
v->push_back(root->data);
// return false if left subtree is not a BST
if (!leftBST) return false;
if (root->right) {
if (root->data < root->right->data) {
// return whether or not the right subtree is a BST
return isBST(root->left, v);
} else {
// the current node violates the BST precondition
return false;
}
}
// everything good, this is a BST
return true;
}
C++ Program to check if tree is BST or not
struct Node
{
int data;
struct Node* left, *right;
};
bool IsBST(Node* ObjNode)
{
bool leftBST = false;
bool rightBST = false;
if( ObjNode->left != null && ObjNode-left < objNode->data)
{
leftBST = IsBST(ObjNode->left)
}
else if( ObjNode->left == null)
{
leftBST = true;
}
else if( ObjNode->left != null && ObjNode-left >= objNode->data)
{
leftBST = false;
}
if( ObjNode->left != null && ObjNode-left < objNode->data)
{
rightBST = IsBST(ObjNode->right)
}
else if( ObjNode->right == null)
{
rightBST = true;
}
else if( ObjNode->right != null && ObjNode-right >= objNode->data)
{
rightBST = false;
}
return (leftBST && rightBST );
}
In the previous solution, they are keeping a list of the inorder traversal, you really don't need it, you can keep checking with the last traversed element and keep moving forward.
Following solution is the fastest
class Solution {
int lastval = Integer.MIN_VALUE;
int count = 0;
public boolean isValidBST(TreeNode root) {
if(root == null) return true;
boolean left = isValidBST(root.left);
if(!left){
return false;
}
int rootVal = root.val;
if(rootVal == -2147483648 && count == 0 ){
rootVal = rootVal + 1;
}
if( rootVal <= lastval){
return false;
}
count ++;
lastval = root.val;
boolean right = isValidBST(root.right);
if(!right){
return false;
}
return true;
}
}