I am writing the the answer for a test sample given in testdome https://www.testdome.com/for-developers/solve-question/9708
The question is about binary search tree:
Binary search tree (BST) is a binary tree where the value of each node is larger or equal to the values in all the nodes in that node's left subtree and is smaller than the values in all the nodes in that node's right subtree.
Write a function that checks if a given binary search tree contains a given value.
For example, for the following tree:
n1 (Value: 1, Left: null, Right: null)
n2 (Value: 2, Left: n1, Right: n3)
n3 (Value: 3, Left: null, Right: null)
Call to contains(n2, 3) should return true since a tree with root at n2 contains number 3.
I modified the code as below, the output looks working well, but the test result tells one fail exist as: Performance test on a large tree: Time limit exceeded
Can you help to modified my mode to fix this fail?
#include <stdexcept>
#include <string>
#include <iostream>
class Node
{
public:
Node(int value, Node* left, Node* right)
{
this->value = value;
this->left = left;
this->right = right;
}
int getValue() const
{
return value;
}
Node* getLeft() const
{
return left;
}
Node* getRight() const
{
return right;
}
private:
int value;
Node* left;
Node* right;
};
class BinarySearchTree
{
public:
static bool contains(const Node& root, int value)
{
Node* tree;
int val = root.getValue();
std::cout<<"current node's value is:"<<val<<'\n';
if (val==value)
{
return true;
}
else if (val>value)
{
tree = root.getLeft();
if(tree != NULL)
{
std::cout<<"left node's value is:"<<tree->getValue()<<'\n';
return contains(*tree, value);
}
else
{
return false;
}
}
else
{
tree = root.getRight();
if(tree != NULL)
{
std::cout<<"right node's value is:"<<tree->getValue()<<'\n';
return contains(*tree, value);
}
else
{
return false;
}
}
//throw std::logic_error("Waiting to be implemented");
}
};
#ifndef RunTests
int main()
{
Node n1(1, NULL, NULL);
Node n3(3, NULL, NULL);
Node n2(2, &n1, &n3);
std::cout << BinarySearchTree::contains(n2, 3);
}
#endif
Remove std::cout will do. Printing to terminal has a huge time cost.
Oh, A better solution here. Why do you want to use temporary variables? While using recursion remember that the temporary variables do get stored on function's calling stack also don't use print statements.
static bool contains(const Node& root, int value)
{
if(root.getValue() == value){
return true;
}
else if(root.getValue() < value && root.getRight() != NULL){
return contains(*(root.getRight()), value);
}
else if(root.getLeft() != NULL){
return contains(*(root.getLeft()), value);
}
return false;
}
Related
I have been scratching my head for a while on this C++ program debug. I'm trying to write a program to help validate if the binary search tree syntax is correct by construction. I'm not a lost for why my program seems to be crashing at the recursive part of the program.
I have a simple Node class:
#include <iostream>
class Node
{
public:
Node(int value, Node* left, Node* right)
{
this->value = value;
this->left = left;
this->right = right;
}
int getValue() const
{
return value;
}
Node* getLeft() const
{
return left;
}
Node* getRight() const
{
return right;
}
private:
int value;
Node* left;
Node* right;
};
Here is the problematic function:
class BinarySearchTree
{
public:
static bool isValidBST(const Node* node) {
std::cout << "DEBUG 1\n";
/* false if left is > than node */
if (node->getLeft() != NULL && node->getLeft()->getValue() > node->getValue())
return false;
std::cout << "DEBUG 2\n";
/* false if right is < than node */
if (node->getRight() != NULL && node->getRight()->getValue() < node->getValue())
return false;
std::cout << "DEBUG 3\n";
/* false if, recursively, the left or right is not a BST */
//std::cout << isValidBST(node->getLeft()) << std::endl;
if (!isValidBST(node->getLeft()) || !isValidBST(node->getRight()))
return false;
/* passing all that, it's a BST */
return true;
}
};
It's called like this:
int main()
{
Node n1(1, NULL, NULL);
Node n3(3, NULL, NULL);
Node n2(2, &n1, &n3);
std::cout << " TEST ";
std::cout << BinarySearchTree::isValidBST(&n2);
std::cout << " DONE " ;
return 0;
}
Your program suffers from too much repetition, and some assumptions about pointers. To begin with, if you call isValidBST(NULL) your program exhibits undefined behavior even though one expects that an empty tree is a valid BST.
Beyond this, your compound conditional statements are duplicating not only pointer test logic, but also the comparisons which it turns out you also did not get correct. You have not considered that duplicate values in a BST are also invalid, and so fixing this logic requires multiple edits.
In general, maintaining identical logic in multiple parts of a program (or a function) adds the potential for future bugs, and it's good to avoid when possible. This is especially true when the duplicated logic is inverted.
Consider the following rearrangement of your function, with the logic in one place:
class BinarySearchTree
{
public:
static bool isValidBST(const Node* node)
{
const Node* prev = NULL;
return isValidBST(node, prev);
}
private:
static bool isValidBST(const Node* node, const Node* &prev)
{
if (!node)
return true;
// Validate left
if (!isValidBST(node->getLeft(), prev))
return false;
// Validate current
if (prev && prev->getValue() >= node->getValue())
return false;
prev = node;
// Validate right
return isValidBST(node->getRight(), prev);
}
};
The function bootstraps a private overload that maintains a pointer of the last value node tested. In this way, you can see the code is vastly simplified and more obvious to the reader.
You need to check that in isValidBST method your node variable is null or not. if node is null and you call
node->getLeft(), node->getRight() or node->getValue()
you will get an error. You need to add null check conditon in isValidBST method
if(node == NULL) return true;
Your can resolve this like
#include <stdexcept>
#include <string>
#include <iostream>
#include <algorithm>
class Node
{
public:
Node(int value, Node* left, Node* right)
{
this->value = value;
this->left = left;
this->right = right;
}
int getValue() const
{
return value;
}
Node* getLeft() const
{
return left;
}
Node* getRight() const
{
return right;
}
private:
int value;
Node* left;
Node* right;
};
class BinarySearchTree
{
public:
static bool isValidBST(const Node* node) {
if(node == NULL) return true;
std::cout << "DEBUG 1\n";
/* false if left is > than node */
if (node->getLeft() != NULL && node->getLeft()->getValue() > node->getValue())
return false;
std::cout << "DEBUG 2\n";
/* false if right is < than node */
if (node->getRight() != NULL && node->getRight()->getValue() < node->getValue())
return false;
std::cout << "DEBUG 3\n";
/* false if, recursively, the left or right is not a BST */
//std::cout << isValidBST(node->getLeft()) << std::endl;
if (!isValidBST(node->getLeft()) || !isValidBST(node->getRight()))
return false;
/* passing all that, it's a BST */
return true;
}
};
#ifndef RunTests
int main()
{
Node n1(1, NULL, NULL);
Node n3(3, NULL, NULL);
Node n2(2, &n1, &n3);
std::cout << " TEST ";
std::cout << BinarySearchTree::isValidBST(&n2);
std::cout << " DONE " ;
return 0;
}
#endif```
I found a logic bug with my recursive program:
needed this extra case with the NULL left and NULL right node.
class BinarySearchTree
{
public:
static bool isValidBST(const Node* node) {
std::cout << "DEBUG 1\n";
/* false if left is > than node */
if (node->getLeft() != NULL && node->getLeft()->getValue() > node->getValue())
return false;
std::cout << "DEBUG 2\n";
/* false if right is < than node */
**if (node->getRight() != NULL && node->getRight()->getValue() < node->getValue())
return false;**
std::cout << "DEBUG 3\n";
if (node->getLeft() == NULL && node->getRight() == NULL) {
return true;
}
/* false if, recursively, the left or right is not a BST */
//std::cout << isValidBST(node->getLeft()) << std::endl;
if (!isValidBST(node->getLeft()) || !isValidBST(node->getRight()))
return false;
/* passing all that, it's a BST */
return true;
}
};```
For binary search tree to see if the tree has duplicated value or not. I took this post order approach.
My goal was to keep the value of the current node and then use other function traverse the tree to see if there is any matching value to that current value, and if it finds any duplicate value it brings "true value". I choose to use recursion as it seems easier to track. but when I ran the program there was no output coming out.
#include "pch.h"
#include <iostream>
using namespace std;
class BSTNode {
public:
int data;
BSTNode* left;
BSTNode* right;
BSTNode() {};
};
BSTNode* newnode(int newdata) { BSTNode *curr = new BSTNode; curr->data = newdata; curr->left = curr->right = nullptr; return curr; }
void print(BSTNode* root) {
if (root != nullptr) {
print(root->left);
cout << root->data << endl;
print(root->right);
}
}
bool checking(BSTNode* parent, int val) {
if (val == parent->data){
bool left = checking(parent->left, val);
bool right = checking(parent->right, val);
return left||right;
}
else
return false;
}
bool assist(BSTNode* parent) {
if (parent != nullptr) {
assist(parent->left);
assist(parent->right);
return checking(parent, parent->data);
}
else return false;
}
int main() {
BSTNode *test = newnode(1);
test->left=newnode(2);
test->right=newnode(3);
test->left->left=newnode(2);
test->right->right=newnode(5);
print(test);
if (assist(test))
cout << "There is duplicated" << endl;
else
cout << "There is no duplicated" << endl;
return 0;
}
Your checking function should look like this:
bool checking(BSTNode* parent, int val) {
if(parent == nullptr) // point 1
return false;
if (val == parent->data){ // point 2
return true;
}
else{
bool left = checking(parent->left, val);
bool right = checking(parent->right, val);
return left||right;
}
}
Your assist function should look something like this:
bool assist(BSTNode* parent) {
if (parent != nullptr) {
if(checking(parent->left, parent->data)) return true; // point 3
if(checking(parent->right, parent->data)) return true;
return assist(parent->left)||assist(parent->right); // point 4
}
else return false;
}
You need to check for null values.
If val is same, why are you still checking? Just stop
You need to check node's value in the left and right subtree.
Recurse it for the child nodes
If you want to check that parent value is different than child values, you might do:
bool checking(const BSTNode* node, int parent_value) {
if (node == nullptr) { return false; }
if (node->data == parent_value) { return true; }
return checking(node->left, node->data)
|| checking(node->right, node->data);
}
bool assist(const BSTNode* parent) {
if (parent == nullptr) {
return false;
}
return checking(parent->left, parent->data)
|| checking(parent->right, parent->data);
}
You could just go through the BST breadth wise with a Deque. Store the values in a set and check if the value is already in the set, if it is return true otherwise wait for the loop to finish and return true. This had the benefit of hash table lookup for values at thr cost of extra storage in O(n) time. Its also easier to follow in my opinion as it's not recursion.
bool hasDuplicate(BSTNode *parent)
{
if (!parent) return false;
std::dueue<BSTNode*> nodes;
std::unordered_set<int> vals;
nodes.push_back(parent);
while(!nodes.empty()) {
BSTNode *node = nodes.pop_front();
int v = nodes->val;
// Check if value exists and return true
if(vals.find(v) != vals.end()) return true;
// Otherwise insert it
vals.insert(v);
// insert left node if exists
if (node->left) nodes.push_back(node->left);
// insert right node if exists
if (node->right) nodes.push_back(node->right);
}
// no dups found
return false;
}
Sorry for bad indents. Did this on phone lol.
Hello i am new to c++ and learning about binary search trees.
I am trying to implement a simple binary search tree where i can store "KeyCodePair" object(which has string and integer) and doing some operations on tree like search and insert. Seems like there are some problems with my logic thats why first Insert function is working but second is not working(calling them from Main) I guess there is problem with the way i implemented "root" where should i write it
This is Tree.cpp:
#include "Tree.h";
#include "KeyCodePair.h";
Tree::Tree() {
treeNode* root = NULL;
}
Tree::treeNode* Tree::getNewNode(KeyCodePair data) {
treeNode* newNode = new treeNode();
newNode->data = data;
newNode->left = newNode->right = NULL;
return newNode;
}
Tree::treeNode* Tree::Insert(KeyCodePair data) {
if (root == NULL) {
root = getNewNode(data);
}
else if (data.getCode() <= root->data.getCode()) {
root->left = Insert(data);
}
else {
root->right = Insert(data);
}
return root;
}
bool Tree::Search(KeyCodePair data) {
if (root == NULL) {
return false;
}
else if (root->data.getCode() == data.getCode()) {
return true;
}
else if (data.getCode() <= root->data.getCode()) {
return Search(data);
}
else {
return Search(data);
}
}
Tree.h:
#ifndef TREE_H
#define TREE_H
#include "KeyCodePair.h"
class Tree {
private:
struct treeNode {
KeyCodePair data;
treeNode* left;
treeNode* right;
} ;
treeNode* root;
public:
treeNode* Insert( KeyCodePair data);
bool Search(KeyCodePair data);
treeNode* getNewNode(KeyCodePair data);
Tree();
};
#endif
KeyCodePair.cpp
#include "KeyCodePair.h"
KeyCodePair::KeyCodePair(string keyparam, int codeparam) {
key = keyparam;
code = codeparam;
}
KeyCodePair::KeyCodePair() {
}
string KeyCodePair::getKey() {
return key;
}
int KeyCodePair::getCode() {
return code;
}
KeyCodePair.h
#ifndef KEYCODEPAIR_H
#define KEYCODEPAIR_H
#include <iostream>
using namespace std;
class KeyCodePair {
private:
string key;
int code;
public:
KeyCodePair();
KeyCodePair(string key, int code);
string getKey();
int getCode();
};
#endif
And Finally this is the main:
#include <iostream>
#include <string>
#include "Tree.h"
#include "KeyCodePair.h"
using namespace std;
int main()
{
Tree tree = Tree();
KeyCodePair testPair = KeyCodePair("teststring1",10);
KeyCodePair qwePair = KeyCodePair("teststring2", 20);
cout << tree.Insert(testPair) << endl;
cout << tree.Insert(qwePair) << endl; // problem on second insert
if (tree.Search(testPair) == true) cout << "Found\n";
else cout << "Not Found\n";
cin.get();
return 0;
}
Let's take a look at your insert function:
Tree::treeNode* Tree::Insert(KeyCodePair data) {
if (root == NULL) {
root = getNewNode(data);
}
else if (data.getCode() <= root->data.getCode()) {
root->left = Insert(data);
}
else {
root->right = Insert(data);
}
return root;
}
What you do here is you take in the data to be inserted, and you look at the root. If there is no root, you add a new node containing the data and assign that to the root (which is why your first insert works). However, once there is a root, you then figure out if the new node should be placed to the left or right of the root, and then recursively call Insert() with the same data. This next call to Insert will do nothing different, and look at the same root of the tree over and over to most likely produce an infinite loop.
What you have to do is using your data, first traverse all the way down the tree to the position at which you want to insert your node, then insert it and assign the pointers. Some code for this might look like so:
Tree::Insert(KeyCodePair data) {
// currPos will end up being the position where we want to insert
Tree::treeNode* currPos = root;
while (currPos != NULL) {
if (data.getCode() <= currPos->data.getCode())
currPos = currPos->left;
else if (data.getCode() > currPos->data.getCode())
currPos = currPos->right;
}
// Insert at currPos and reassign the left or right pointer of
// the parent
}
The problem is that your insert only considers the root node. You need to traverse down the tree to the point where you do the insert:
class Tree {
...
public:
treeNode* Insert(KeyCodePair data);
...
};
Step 1: Change your interface
class Tree {
...
// The insert that does the work
// We pass in the current position in the tree.
treeNode* Insert(treeNode* node, KeyCodePair data);
public:
// The public interface that accepts the data and calls the internal Insert
void Insert(KeyCodePair data);
...
};
Step 2: Use the public Insert to call the internal Insert.
void Tree::Insert(KeyCodePair data) {
// Use the internal Insert() passing the root as the starting point.
// If a new value is needed it will be returned otherwise the original
// value is returned.
root = Insert(root, data);
}
Step 3: Modify the OP Insert into an Internal Insert.
Tree::treeNode* Tree::Insert(treeNode* node, KeyCodePair data) {
if (node == NULL) {
// If we have reached the tip of the tree then
// return the new node so it can be inserted.
return getNewNode(data);
}
// Otherwise we have a node so we need to find the node
// were the data will be inserted.
// so move to the next level. Assign the result as the next
// level could be null.
if (data.getCode() <= root->data.getCode()) {
node->left = Insert(node->left, data);
}
else {
node->right = Insert(node->right, data);
}
// Return this node
// So it stays in the chain.
return node;
}
I have a problem when implementing BST in C++. When I insert a small data around 20,000 data to the BST, it runs well. If I try to insert a big number of data around 100,000. The BST get an runtime error. Can you guys help me?
This is my implementation.
Binary Search.h
#include <iostream>
#include <stdlib.h>
#include <conio.h>
using namespace std;
struct treeNode
{
long long data;
treeNode *left;
treeNode *right;
};
treeNode *insertNode(treeNode *node,long long data)
{
if(node==NULL)
{
treeNode *temp = new treeNode;
//temp = (treeNode *)malloc(sizeof(treeNode));
temp -> data = data;
temp -> left = temp -> right = NULL;
return temp;
}
if(data >(node->data))
{
node->right = insertNode(node->right,data);
}
else if(data < (node->data))
{
node->left = insertNode(node->left,data);
}
/* Else there is nothing to do as the data is already in the tree. */
return node;
}
treeNode * searchNode(treeNode *node, long long data)
{
if(node==NULL)
{
/* Element is not found */
return NULL;
}
if(data > node->data)
{
/* Search in the right sub tree. */
return searchNode(node->right,data);
}
else if(data < node->data)
{
/* Search in the left sub tree. */
return searchNode(node->left,data);
}
else
{
/* Element Found */
return node;
}
}
void displayInorder(treeNode *node)
{
if(node==NULL)
{
return;
}
displayInorder(node->left);
cout<<" " << node->data<<" ";
displayInorder(node->right);
}
void displayPreorder(treeNode *node)
{
if(node==NULL)
{
return;
}
cout<<" " <<node->data<<" ";
displayPreorder(node->left);
displayPreorder(node->right);
}
void displayPostorder(treeNode *node)
{
if(node==NULL)
{
return;
}
displayPostorder(node->left);
displayPostorder(node->right);
cout<<" " <<node->data<<" ";
}
I get the run time error at :
node->right = insertNode(node->right,data);
Please do help me guys.
Thank you in advance!
You're likely running out of stack with all the recursion, so you could either increase the stack, or write some (or all) of your functions to use iteration instead of recursion (although preorder, postorder, inorder traversals are hard to write correctly as loops).
Here's a simple example for the Search and Insert methods:
struct TreeNode
{
long long data = 0;
std::shared_ptr<TreeNode> left;
std::shared_ptr<TreeNode> right;
TreeNode(long long _data) : data(_data){}
};
class BST
{
public:
void Insert(std::shared_ptr<TreeNode> node)
{
if (!node)
throw std::runtime_error("Cannot insert null node");
if (!root)
{
root = node;
return;
}
std::shared_ptr<TreeNode>* next = &root;
while(*next)
{
if (node->data < (*next)->data)
next = &((*next)->left);
else
next = &((*next)->right);
}
*next = node;
}
std::pair<bool, std::shared_ptr<TreeNode>> Search(long long data)
{
if (!root)
return std::make_pair(false, nullptr); // searching empty tree
std::shared_ptr<TreeNode> next = root;
while(next)
{
if (data < next->data)
next = next->left;
else if (data > next->data)
next = next->right;
else
return std::make_pair(true, next); // match found
}
// no match found
return std::make_pair(false, nullptr);
}
private:
std::shared_ptr<TreeNode> root;
};
A full working demo can be found here
This is a binary search tree implementation, I cant figure out why my min method (for finding the minimum element in a tree) is not returning the correct answer, but an arbitrary memory address.
I am creating a tree by this constructor BST(3);, now I run min(), it returns correctly 3, but after inserting 1(insert(1) method), min() returns some hex address.
class node{
public:
int key;
node *left;
node *right;
node *parent;
};
class BST{
node *root;
public:
BST(){}
BST(int a){
root=new node();
root->left=NULL;
root->right=NULL;
root->parent=NULL;
root->key=a;
}
void insert(int n)
{
if(search(n))return;
node *p=root;
node *m=new node;
m->key=n;
m->left=NULL;
m->right=NULL;
while(1)
{
if(p->key > n)
{
//look left
if(p->left==NULL)
{
p->left=m;
m->parent=p;
return;
}
else
p=p->left;
}
else
{
//look right
if(p->right==NULL)
{
p->right=m;
m->parent=p;
return;
}
else
p=p->right;
}
}
}
bool search(int n)
{
node *p=root;
while(1)
{
if(p->key > n)
{
//look left
if(p->left==NULL)
return false;
else
p=p->left;
}
else if(p->key==n)return true;
else
{
//look right
if(p->right==NULL)
return false;
else
p=p->right;
}
}
}
int min()
{
node *p=root;
if(p->left == NULL)
return (p->key);
p=p->left;
}
};
Because you run into undefined behaviour by not returning on all control paths:
int min()
{
node *p=root;
if(p->left == NULL)
return (p->key);
p=p->left;
//no return here
}
Which means that if p->left is not NULL, anything can happen. Anything!
It looks like you want a loop there instead:
int min()
{
node *p=root;
while (p->left != NULL)
p=p->left;
return (p->key);
}
If p->left != NULL, you don't return anything.